Access-Control-Allow-Origin is not shown even I added in server - node.js

server side
const express = require("express");
const socket = require("socket.io");
const http = require("http");
const { addUser, removeUser, getUser, getUsersInRoom } = require("./user");
const PORT = process.env.PORT || 8000;
// 2. 라우터 설정
const router = require("./router");
const app = express();
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3001");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE");
res.setHeader("Access-Control-Allow-Headers", "X-Requested-With,content-type");
res.setHeader("Access-Control-Allow-Credentials", true);
next();
});
const server = http.createServer(app);
const io = socket(PORT);
io.on("connection", (socket) => {
console.log("소켓 연결 완료");
socket.on("join", ({ name, room }, callback) => {
const { error, user } = addUser({ id: socket.id, name, room });
if (error) return callback(error); // username taken
socket.join(user.room);
socket.emit("message", {
user: "admin",
text: `${user.name}, welcome to the room ${user.room}`,
});
socket.broadcast
.to(user.room)
.emit("message", { user: "admin", text: `${user.name}, has joined!` });
io.to(user.room).emit("roomData", {
room: user.room,
users: getUsersInRoom(user.room),
});
callback();
});
socket.on("sendMessage", (message, callback) => {
const user = getUser(socket.id);
io.to(user.room).emit("message", { user: user.name, text: message });
// callback();
});
socket.on("disconnect", () => {
const user = removeUser(socket.id);
console.log("유저가 떠났습니다..");
if (user) {
io.to(user.room).emit("message", {
user: "Admin",
text: `${user.name} has left.`,
});
io.to(user.room).emit("roomData", {
room: user.room,
users: getUsersInRoom(user.room),
});
}
});
});
app.use(router);
server.listen(PORT, () => console.log(`server has started on port ${PORT}`));
and this is client side
import React, { useEffect, useState } from "react";
import queryString from "query-string";
import io from "socket.io-client";
import "./Chat.css";
// 하위 컴포넌트
import Messages from "../Messages/Messages";
import RoomInfo from "../RoomInfo/RoomInfo";
import Input from "../Input/Input";
let socket;
const Chat = ({ location }) => {
const [name, setName] = useState("");
const [room, setRoom] = useState("");
const [message, setMessage] = useState("");
const [messages, setMessages] = useState([]);
const [users, setUsers] = useState("");
const ENDPOINT = "http://localhost:8000/";
useEffect(() => {
const { name, room } = queryString.parse(location.search);
socket = io.connect(ENDPOINT); // 소켓 연결
setName(name);
setRoom(room);
console.log(name, room); // lama peru
// console.log(socket);
socket.emit("join", { name, room }, (error) => {
// console.log("error");
// 에러 처리
if (error) {
alert(error);
}
});
}, [ENDPOINT, location.search]);
useEffect(() => {
// 서버에서 message 이벤트가 올 경우에 대해서 `on`
socket.on("message", (message) => {
setMessages([...messages, message]);
});
socket.on("roomData", ({ users }) => {
setUsers(users);
});
}, [messages]);
// 메세지 보내기 함수
const sendMessage = (e) => {
e.preventDefault();
if (message) {
socket.emit("sendMessage", message, setMessage(""));
}
};
console.log(message, messages);
console.log(users, "users");
return (
<div className="chatOuterContainer">
<div className="chatInnerContainer">
<div className="appbar"></div>
<div className="chatScreen">
<div className="chatScreen">
<RoomInfo room={room} />
<div className="messageContainer">
<Messages messages={messages} name={name} />
</div>
<Input message={message} setMessage={setMessage} sendMessage={sendMessage} />
</div>
</div>
</div>
</div>
);
};
export default Chat;
and when I try the website I get this
[enter image description here][1]
as you can see there's no Access-Control-Allow-Origin in response header..
I start my project by following.
first start server by 'node server.js'
start client by command 'yarn start'
the cors options don't seem to apply.
[1]: https://i.stack.imgur.com/QpQ7o.png
would be very thankful if you help me!

try this:
app.all('/*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Credentials", "true")
res.header("Access-Control-Allow-Headers", "Origin,X-Requested-With,Content-Type,Accept,Authorization")
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,PATCH,OPTIONS")
next()
})

Related

Create private chat with MERN and Socketio

i want to send message to specific user from react-autocomplete dropdown menu with select and display that message in their own window. And also i am trying to save messages to my mongodb but when i check mongocompass server it is only showing me the _id and and when i click send button in front end it is sending same message multiple times .Here is what i have so far but it is sending the message to everyone. i need help to get my code right to create private chat with saving correctly to db and retrieve messages everytime page refreshes
CLIENT:
const [username, setUsername] = useState("");
const [onlineUsers, setOnlineUsers] = useState([]);
const [chatHistory, setChatHistory] = useState([]);
const ADDRESS = "http://localhost:1337";
const socket = io(ADDRESS, { transports: ["websocket"] });
useEffect(() => {
socket.on("connect", () => {
console.log("Connection established!");
});
socket.on("loggedIn", () => {
console.log("Successfully logged in");
fetchOnlineUsers();
});
socket.on("newConnection", () => {
console.log("Look! another client connected!");
fetchOnlineUsers();
});
socket.on("message", (newMessage) => {
console.log("new message received!", newMessage);
setChatHistory((currentChatHistory) => [
...currentChatHistory,
newMessage,
]);
});
}, []);
const handleSubmitMessage =(e)=> {
e.preventDefault();
const messageToSend = {
text: message,
sender: username,
id: socket.id,
timeStamp: Date.now()
}
socket.emit("sendmessage", messageToSend)
setChatHistory([...chatHistory, messageToSend])
setMessage("")
}
const handleOnSearch = (string, results) => {}
const handleOnHover = (result) => {}
const handleOnSelect = (item) => {
console.log("ITEM",item);
}
const handleOnFocus = () => {}
const formatResult = (item) => {
return (
<>
<span style={{ display: 'block', textAlign: 'left' }}>{item.username}</span>
</>
)
}
SERVER CODE
import express from "express";
import cors from "cors";
import mongoose from "mongoose";
import listEndpoints from "express-list-endpoints";
import { Server } from "socket.io";
import { createServer } from "http";
import MsgModel from './db/schema.js'
const { MONGO_URL } = process.env;
const app = express();
app.use(cors());
app.use(express.json());
const server = createServer(app);
const io = new Server(server);
const port = process.env.PORT || 1337;
let onlineUsers = [];
io.on("connect", (socket) => {
socket.join("main-room")
socket.on("setUsername", ({ username }) => {
onlineUsers = onlineUsers
.filter((user) => user.username !== username)
.concat({
username: username,
id: socket.id,
});
socket.emit("loggedIn");
socket.broadcast.emit("newConnection");
});
socket.on("sendmessage", (msg) => {
console.log("sendmessage",msg);
const saveMessageToDb = new MsgModel({msg:msg})
saveMessageToDb.save().then(()=> {
socket.to("main-room").emit("message", msg)
})
})
app.get("/online-users", (req, res) => {
res.send({ onlineUsers });
});
MONGOOSE SCHEMA
import mongoose from "mongoose";
const { Schema, model } = mongoose;
const msgSchema = new Schema(
{
msg: { type: String },
},
{ typeKey: '$type' }
);
export default model("Message", msgSchema);

socket.io insufficient resources - react js and node

I'm experimenting a bit with socket.io to create a chat app in real time.
Everything seems to work fine but after a few second socket.io gives me this error:
"websocket.js:50 WebSocket connection to 'ws://localhost:5000/socket.io/?EIO=4&transport=websocket&sid=gbx90aAo73oDoP86AAVP' failed: Insufficient resources"
What am I doing wrong?
Client
import React from "react";
import { useState, useEffect } from "react";
import { io } from "socket.io-client";
const App = () => {
const [conv, setConv] = useState([]);
const [input, setInput] = useState({
sender: "user",
text: "",
});
const socket = io("http://localhost:5000");
const handleChange = (e) => {
setInput({
sender: "user",
text: e.target.value,
});
};
const handleSubmit = (e) => {
e.preventDefault();
socket.emit("input", input);
};
useEffect(() => {
socket.on("output", (data) => {
setConv(data[0].messages);
});
}, [conv]);
return (
<div className="App">
<form onSubmit={handleSubmit}>
<h1>chat</h1>
<div id="messages">
{conv.map((msg, index) => (
<div key={index}>
<p>
{msg.sender}: {msg.text}
</p>
</div>
))}
</div>
<input onChange={handleChange} type="text" />
<input type="submit" />
</form>
</div>
);
};
export default App;
Server
const express = require("express");
const socketIo = require("socket.io");
const http = require("http");
const PORT = 5000;
const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
cors: {
origin: "http://localhost:3000",
},
}); //in case server and client run on different urls
const MongoClient = require("mongodb").MongoClient;
MongoClient.connect("mongodb://localhost:27017", (err, db) => {
if (err) throw err;
console.log("connected");
const database = db.db("local");
const chat = database.collection("chat");
//connect to socket .io
io.on("connection", (socket) => {
// get chat from collection
chat.find().toArray((err, res) => {
if (err) throw err;
// emit the messages
socket.emit("output", res);
});
//handle input events
socket.on("input", (input) => {
let sender = input.sender;
let receiver = "bot";
let text = input.text;
// check if inside chat collection the members array contains the sender and receiver
chat.find({ members: { $all: [sender, receiver] } }).toArray((err, res) => {
if (err) throw err;
let senderInDb = res[0].members[0];
let receiverInDb = res[0].members[1];
//if yes then push the message to the messages array
if (sender === senderInDb && receiver === receiverInDb) {
chat.updateOne(
{ members: { $all: [sender, receiver] } },
{ $push: { messages: { sender: sender, text: text } } }
);
}
});
});
});
});
server.listen(PORT, (err) => {
if (err) console.log(err);
console.log("Server running on Port ", PORT);
});

How to use socketio inside controllers?

I have a application created with Reactjs,Redux,Nodejs,MongoDB. I have created socketio in backend side.
server.js
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const app = express();
const routes = require('./routes/api/routes');
var server = require('http').Server(app);
const io = require('./socket').init(server);
app.use(express.json());
require('dotenv').config();
mongoose.connect(process.env.MONGO_DB).then(console.log('connected'));
const corsOptions = {
credentials: true, //access-control-allow-credentials:true
optionSuccessStatus: 200,
};
app.use(cors(corsOptions));
app.use(routes);
if (
process.env.NODE_ENV === 'production' ||
process.env.NODE_ENV === 'staging'
) {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
io.on('connection', (socket) => {
console.log('New client connected');
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
server.listen(process.env.PORT || 5000, () => {
console.log('socket.io server started on port 5000');
});
socket.js
let io;
module.exports = {
init: (httpServer) => {
return (io = require('socket.io')(httpServer, {
cors: {
origin: 'http://localhost:3000',
methods: ['GET', 'POST'],
},
}));
},
getIO: () => {
if (!io) {
throw new Error('Socket.io is not initialized');
}
return io;
},
};
In controller.js I am creating new item to inside mongodb and also using socketio. I am emitting new Item that I created. It looks like that
controller.js
const createTeam = async (req, res) => {
const userId = req.user.id;
const newItem = new Item({
name: req.body.name,
owner: userId,
});
await newItem.save((err, data) => {
if (err) {
console.log(err);
return res.status(500).json({
message: 'Server Error',
});
}
});
await newItem.populate({
path: 'owner',
model: User,
select: 'name',
});
await User.findByIdAndUpdate(
userId,
{ $push: { teams: newItem } },
{ new: true }
);
io.getIO().emit('team', {
action: 'creating',
team: newItem,
});
res.json(newItem);
};
In frontend side I am listening the socketio server with socket.io-client. In my App.js I can see data that come from backend side when I console.log(data). My app working perfect until this stage. I can take the data from socketio, I can see the new client that connected. But when I send the data with dispatch, I app start to add infinite new items to database. Take a look at my App.js
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import { AppNavbar } from './components/AppNavbar';
import { TeamList } from './components/TeamList';
import { loadUser } from './Store/Actions/AuthActions';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { io } from 'socket.io-client';
import { addItems } from './Store/Actions/itemActions';
function App() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(loadUser());
const socket = io('http://localhost:5000');
socket.on('team', (data) => {
if (data.action === 'creating') {
dispatch(addItems(data.team));
}
// console.log(data);
});
}, []);
return (
<div className="App">
<AppNavbar />
<TeamList />
</div>
);
}
export default App;
My itemAction in redux side is also like that
export const addItems = (input) => (dispatch, getState) => {
axios
.post('/api/items/createTeam', input, tokenConfig(getState))
.then((res) =>
dispatch({
type: ADD_ITEM,
payload: res.data,
})
)
.catch((err) =>
dispatch(
returnErrors(err.response.data, err.response.status, 'GET_ERRORS')
)
);
};
My problem is how to stop infinite callling of api after implement socketio. How to stop infinite loop efficiently?
Infinite loop is steming from not dispatching "type: ADD_ITEM" once.This issue cause that your itemAction always would dispatch "type: ADD_ITEM" and payload with it when after every fetching then your react would re-render page again and again.
You should get rid of your dispatching action inside of addItems function and dispatch your action only inside of useEffect in App.js file .
Your code snippet should look like this in App.js:
useEffect(() => {
//...
const socket = openSocket('http://localhost:5000');
socket.on('postsChannel', (data) => {
if (data.action === 'creating') {
dispatch({ type: ADD_ITEM, payload: data.team });
}
});
}, [dispatch]);

Multiple listeners & removeListener removes everything Socket.io

Folks! I am writing a socket.io chat. When the user sends a message, the socket.on event occurs. Everything works, but the amount of listeners is growing exponentially. I tried to remove the listener with socket.off/socket.remove..., take out the event socket.on separately from connection - nothing works. Please, please help me figure it out. I`m using react, node, socket & mongoDB
Server part:
const express = require("express");
const app = express();
const cors = require("cors");
const { UserModel } = require("./models");
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.options("http://localhost:3000", cors());
const mongoose = require("mongoose");
require("dotenv").config();
const http = require("http").createServer(app);
const io = require("socket.io")(http, {
cors: {
origin: ["http://localhost:3002"],
},
});
http.listen(3001, function () {
console.log("Server is running");
});
io.on("connection", (socket) => {
console.log("Socket connected", socket.id);
socket.on("message:send", (data) => {
console.log("Пришло в socket.onMessage", data);
socket.emit("message:fromServer", data);
// socket.removeListener("message:fromServer");
});
});
const { userApi } = require("./api/userApi");
app.use("/", userApi);
app.use((err, _, res, __) => {
return res.status(500).json({
status: "fail",
code: 500,
message: err.message,
});
});
const { PORT, DB_HOST } = process.env;
const dbConnection = mongoose.connect(DB_HOST, {
useNewUrlParser: true,
useFindAndModify: false,
useCreateIndex: true,
useUnifiedTopology: true,
});
dbConnection
.then(() => {
console.log("DB connect");
app.listen(PORT || 3000, () => {
console.log("server running");
});
})
.catch((err) => {
console.log(err);
});
Client part:
io.js
import { io } from "socket.io-client";
export const socket = io("http://localhost:3001/");
Message component
import React from "react";
import { useState } from "react";
// import { useSelector } from "react-redux";
// import { getMessages } from "../../Redux/selectors";
import { socket } from "../helpers/io";
import Message from "../Message/Message";
import { nanoid } from "nanoid";
export default function MessageFlow() {
const [message, setMessage] = useState([]);
socket.on("message:fromServer", (data) => {
console.log("На фронт пришло сообщение: ", data);
setMessage([...message, data]);
// setMessage((message) => [...message, data]);
console.log("Массив сообщений компонента MessageFlow", message);
console.log(socket.io.engine.transports);
// socket.off();
// getEventListeners(socket)['testComplete'][0].remove()
// socket.removeListener("message:fromServer");
});
// const dispatch = useDispatch();
// const allMessages = useSelector(getMessages);
return (
<div id="mainDiv">
{message &&
message.map((i) => {
// return <Message />;
return <Message content={i.userId} id={nanoid()} />;
})}
</div>
);
}
Message Form - the beginning of emitting process
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { sendMessage } from "../../Redux/Chat/Chat-operations";
import { getUser } from "../../Redux/selectors";
import { getToken } from "../../Redux/Auth/Auth-selectors";
import { socket } from "../helpers/io";
import { useEffect } from "react";
import styles from "./MessageForm.module.css";
export default function MessageForm() {
const [message, setMessage] = useState("");
const dispatch = useDispatch();
const userId = useSelector(getUser);
const currentToken = useSelector(getToken);
// const getAll = useSelector(allContacts);
const updateMessage = (evt) => {
setMessage(evt.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (message) {
socket.emit("message:send", { userId: message });
dispatch(
sendMessage(
{
_id: userId,
text: message,
},
currentToken
)
);
} else {
alert(`Молчать будем?`);
}
};
return (
<div className={styles.messageInputContainer}>
<form>
<input
type="text"
value={message}
onChange={updateMessage}
required
className={styles.messageInput}
placeholder="Type message to send"
/>
<button
type="submit"
className={styles.messageAddBtn}
onClick={handleSubmit}
>
Send
</button>
</form>
</div>
);
}
You add a listener on every render, you should use useEffect hook
export default function MessageFlow() {
useEffect(()=>{ // triggered on component mount or when dependency array change
const callback = (data) => {
// what you want to do
}
socket.on("message:fromServer", callback);
return () => { // on unmount, clean your listeners
socket.removeListener('message:fromServer', callback);
}
}, []) // dependency array : list variables used in your listener
// [...]
}

Browsers hangs while using Socket.io with ReactJS and ExpressJS

Problem:
I am working on a chat application. When I send more than 9-10 requests, the browser slows down and eventually, it just hangs. On refreshing the page, everything is back to normal.
I searched the socket.io documentation but couldn't get any solution regarding this matter.
Code:
Here is my Backend Express.JS code:
index.js
const express = require("express");
const { addUser, getUser, deleteUser, getAllUsers } = require("./users_api");
const app = express();
const server = require("http").createServer(app);
const io = require("socket.io")(server, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
},
});
const port = 5000 || process.env.PORT;
io.on("connection", (socket) => {
socket.on("join", ({ name, room }, callback) => {
const { err, user } = addUser({ id: socket.id, name, room });
if (err) return callback(err);
if (user) {
socket.emit("message", {
user: "admin",
text: `${user.name} has entered the room ${user.room}.`,
});
socket.broadcast.to(user.room).emit("message", {
user: "admin",
text: `${user.name} has joined the room.`,
});
socket.join(user.room);
io.to(user.room).emit("users", {
room: user.room,
users: getAllUsers(user.room),
});
callback();
}
});
socket.on("client_message", (msg) => {
const user = getUser(socket.id);
if (user) io.to(user.room).emit("message", { user: user.name, text: msg });
});
socket.on("disconnect", () => {
console.log(6);
const user = deleteUser(socket.id);
if (user) {
io.to(user.room).emit("message", {
user: "admin",
text: `${user.name} has left the room.`,
});
io.to(user.room).emit("users", {
room: user.room,
users: getAllUsers(user.room),
});
}
});
});
server.listen(port, () => console.log(`Server started at port ${port}.`));
users_api.js:
const current_users = [];
const addUser = ({ id, name, room }) => {
name = name.trim().toLowerCase().split(" ").join("_");
room = room.trim().toLowerCase();
const exist_user = current_users.find(
(user) => name === user.name && room === user.room
);
if (exist_user)
return {
err: "User with this name already exists.",
};
current_users.push({ id, name, room });
return { user: { id, name, room } };
};
const deleteUser = (id) => {
const index = current_users.findIndex((user) => user.id === id);
if (index !== -1) return current_users.splice(index, 1)[0];
};
const getUser = (id) => current_users.find((user) => user.id === id);
const getAllUsers = (room) =>
current_users.filter((user) => user.room === room);
module.exports = { addUser, deleteUser, getUser, getAllUsers };
Front-end Code:
import io from "socket.io-client";
import React, { useEffect, useRef, useState } from "react";
import queryString from "query-string";
import "./ChatPage.css";
const END_POINT = "http://localhost:5000";
const ChatPage = (props) => {
const [message, setMessage] = useState("");
const [messages, setMessages] = useState([]);
const [users, setUsers] = useState([]);
const socket = useRef(null);
const handleSubmit = () => {
socket.current.emit("client_message", message);
setMessage("");
};
useEffect(() => {
const { name, room } = queryString.parse(props.location.search);
socket.current = io(END_POINT);
socket.current.emit("join", { name, room }, (error) => {
if (error) alert(error);
});
return () => {
socket.current.disconnect();
socket.current.off();
};
}, [props.location.search, END_POINT]);
useEffect(() => {
socket.current.on("message", (msg) => {
setMessages([...messages, msg]);
});
socket.current.on("users", ({ users }) => {
setUsers(users);
});
}, [messages.length]);
return (
<div className="chat-room-container">
<div className="chat-room-left">
<ul>
{messages.map((message, i) => (
<li key={i}>
{message.name}
{message.text}
</li>
))}
</ul>
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
<button type="button" onClick={handleSubmit}>
Submit
</button>
</div>
<div className="chat-room-right">
<ul>
{users.map((user, i) => (
<li key={i}>{user.name}</li>
))}
</ul>
</div>
</div>
);
};
export default ChatPage;
I don't understand what's wrong, please help.
Instead of sending a message on event or broadcast try to send list of messages to particular user or all users list with their messages belonging to same room. This will leads to less render in frontend.
For example,
Your Frontend code will change like,
useEffect(() => {
socket.current.on("message", (msgList) => {
setMessages(msgList);
});
socket.current.on("users", ({ users }) => {
setUsers(users);
});
}, [messages.length]);
Also if different rooms then there occurs a problem to filter the messages. So to solve this there are two possible ways:
When you send filter data from server.
Filter data in client according to user name and room name.
As this solution is not a good practice as every time the whole list of message will come and applying filter on that will increase time complexity. But you can reduce to some extent by making proper structure of data state on server.
I think this will help you.
You are creating new socket connection on every useEffect, so after ten messages, you have ten connections.
socket = io(END_POINT);
I store the created socket connection in useRef - so if it is created again, it is overwritten with the new one - and it does not duplicate.
const socketConection = useRef(null)
useEffect(() => {
socketConnection.current = io(END_POINT)
}, [deps])
Of course, in all following uses you have to use socketConection.current

Resources