I have my backend in NodeJS and frontend in NextJS. As soon I try to connect with the server for a WebSocket connection, the server connects the socket and immediately disconnects it.
This is what I get on my server as soon as I reload my frontend page:
user connected ---- OKGG9r0qvvBs0EWeAAAB test#test.com socket disconnected--- OKGG9r0qvvBs0EWeAAAB test#test.com
This is my server code:
import express from "express";
import dotenv from "dotenv";
import http from "http";
import { Server, Socket } from "socket.io";
import userRoutes from "./routes/users";
import { DefaultEventsMap } from "socket.io/dist/typed-events";
dotenv.config();
const PORT = process.env.PORT || 5000;
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: process.env.CLIENT_URL,
},
});
app.use(express.json());
app.get("/ping", (req, res) => res.status(200).send("Pong"));
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Methods", "POST, GET");
res.header(
"Access-Control-Allow-Headers",
"Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
);
next();
});
interface SType extends Socket {
email?: string;
}
io.use((socket: SType, next) => {
const userEmail = socket.handshake.auth.email;
if (!userEmail) {
return next(new Error("Invalid email"));
}
console.log("userEmail-----", userEmail);
socket.email = userEmail;
next();
});
io.on("connection", (socket) => {
const users = [];
for (let [id, socket] of io.of("/").sockets) {
users.push({
userID: id,
email: (socket as any).email,
});
socket.emit("users", users);
}
socket.broadcast.emit("user connected", {
userID: socket.id,
email: (socket as any).email,
});
console.log("user connected ---- ", socket.id, (socket as any).email);
socket.on("disconnect", () => {
console.log("socket disconnected---", socket.id, (socket as any).email);
(socket as any).email = "";
});
});
app.use("/users", userRoutes);
server.listen(PORT, () => console.log(`server running on port ${PORT}`));
this is code on client side
useEffect(() => {
if (userState) {
socket.auth = { email: userState.email };
}
}, [userState]);
useEffect(() => {
socket.on("users", (users: any) => {
console.log("users", users);
setUsers(users);
});
socket.on("user connected", (user: any) => {
setUsers((previousState: any) => [...previousState, user]);
});
}, [socket]);
I tried the solutions from stack overflow as well as socket.io documentation, but nothing seems to work. Does anyone know what is happening here?
Related
i'm developing a chat app in express by socket.io and this is my code:
well the front end cannot connect to socket io but server is running and i can login
const express = require("express");
const { Server } = require("socket.io");
const helmet = require("helmet");
const cors = require("cors");
const authRouter = require("./routes/authRouter");
const { corsConfig } = require("./controllers/serverController");
const {
Authorization,
AddFriend,
Disconnect,
dm,
} = require("./controllers/socketController");
require("dotenv").config();
const app = express();
const server = require("http").createServer(app);
const io = new Server(server, {
cors: corsConfig,
});
app.use(helmet());
app.use(cors(corsConfig));
app.use(express.json());
//! Routes
app.use("/auth", authRouter);
app.get("/", (req, res) => res.send("Hi"));
io.use(Authorization);
io.on("connection", (socket) => {
console.log("socket")
socket.on("add_friend", (friendName, cb) => {
AddFriend(socket, friendName, cb);
});
socket.on("disconnect", Disconnect);
socket.on("dm", (message) => dm(socket, message));
});
server.listen(5050, () => {
console.log(app.get("env"));
});
but my server isnt running on localhost:5050 this is the error i got :
curl "http://localhost:5050/socket.io/?EIO=4&transport=polling" curl: (7) Failed to connect to localhost port 5050: Connection refused
ive tried to change config of socket server but none of those worked
i have a socketjs file which will create my config and a useEffect hook which inside that ive tried to connect to my server
frontendCode:
socket.js
import { io } from "socket.io-client";
const socket = (user) =>
new io("http://localhost:5050", {
autoConnect: false,
withCredentials: true,
auth: {
token: user.token,
},
});
export default socket;
useSocket.js:
socket.connect();
socket.on("friends", (FriendList) => {
setFriendList(FriendList);
});
socket.on("messages", (messages) => {
setMessages(messages);
});
socket.on("dm", (message) => {
setMessages((prev) => [message, ...prev]);
});
socket.on("connected", (status, username) => {
setFriendList((prev) => {
const friends = [...prev];
return friends.map((friend) => {
if (friend.username === username) {
friend.status = status;
}
return friend;
});
});
});
socket.on("connect_error", () => {
setUser({ loggedIn: false });
});
returned error from frontend:
Firefox can’t establish a connection to the server at ws://localhost:5050/socket.io/?EIO=4&transport=websocket&sid=1uKM4znamAHH8P6kAAKY.
index.ts
import { Server } from "./server";
const server = new Server();
server.listen(port => {
console.log(`Server is listening on http://localhost:${port}`);
});
server.ts
import express, { Application } from "express";
import { Server as SocketIOServer } from "socket.io";
// import { Server as HTTPServer } from "http";
import { Server as HTTPSServer } from "https";
import path from "path";
// for https
const https = require('https');
const fs = require('fs');
export class Server {
private httpServer: HTTPSServer;
private app: Application;
private io: SocketIOServer;
// private activeSockets: string[] = [];
private activeSockets = {};
private readonly DEFAULT_PORT = 5000;
constructor() {
this.initialize();
}
private initialize(): void {
this.app = express();
// this.httpServer = createServer(this.app);
this.app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// https
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
this.httpServer = https.createServer(options, this.app);
this.io = require("socket.io")(this.httpServer, {
handlePreflightRequest: (req, res) => {
const headers = {
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Allow-Origin": req.headers.origin, //or the specific origin you want to give access to,
"Access-Control-Allow-Credentials": true
};
res.writeHead(200, headers);
res.end();
}
});
//this.io.origins('*:*');
this.configureApp();
this.configureRoutes();
this.handleSocketConnection();
}
private configureApp(): void {
this.app.use(express.static(path.join(__dirname, "../public")));
}
private configureRoutes(): void {
this.app.get("/", (req, res) => {
res.sendFile("index.html");
});
this.app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "*");
next();
});
}
private handleSocketConnection(): void {
this.io.on("connection", socket => {
var client_name = socket.handshake.query.name;
const existingSocket = this.activeSockets.hasOwnProperty(socket.id);
console.log("query parameter:")
console.log(client_name);
if (!existingSocket) {
// add the socket id to active socket list
this.activeSockets[socket.id] = { 'bot_id': client_name, 'service_status': 0 };
console.log("Active sockets" + JSON.stringify(this.activeSockets));
// send the u[dated list to all connected users
socket.emit("update-user-list", {
users: this.activeSockets
});
socket.broadcast.emit("update-user-list", {
// users: [socket.id]
users: this.activeSockets
});
}
socket.on("call-user", (data: any) => {
socket.to(data.to).emit("call-made", {
offer: data.offer,
socket: socket.id
});
});
socket.on("candidate", (data: any) => {
socket.to(data.to).emit("candidate", {
candidate: data.candidate,
socket: socket.id
});
});
socket.on("make-answer", data => {
socket.to(data.to).emit("answer-made", {
socket: socket.id,
answer: data.answer
});
});
socket.on("reject-call", data => {
socket.to(data.from).emit("call-rejected", {
socket: socket.id
});
});
socket.on("disconnect", () => {
// this.activeSockets = this.activeSockets.filter(
// existingSocket => existingSocket !== socket.id
// );
console.log("deleteing socket: ");
console.log(socket.id);
delete this.activeSockets[socket.id];
socket.broadcast.emit("remove-user", {
socketId: socket.id
});
});
socket.on("sdp", data => {
console.log("in sdp");
console.log(data);
socket.to(data.to).emit("sdp", {
sdp: data.sdp
});
});
});
}
public listen(callback: (port: number) => void): void {
this.httpServer.listen(this.DEFAULT_PORT, () => {
callback(this.DEFAULT_PORT);
});
}
}
This script exports a Server class that creates an HTTPS server using the https module, and sets up an Express application, a Socket.IO server, and some routes and handlers.
On instantiation, the Server class calls the initialize method which sets up an Express application, creates an HTTPS server using the https module and passes the application as a callback, creates a Socket.IO server by passing the HTTPS server as an argument, sets up some CORS headers, calls the configureApp and configureRoutes methods, and handleSocketConnection method.
The configureApp method sets up the Express app to serve static files from a public directory, and the configureRoutes method sets up a route for the root URL that sends the index.html file and sets CORS headers.
The handleSocketConnection method sets up event handlers for the connection, call-user, and make-answer events. It also uses the activeSockets object to keep track of connected clients, and emits updates to all connected clients when a new client connects or disconnects.
I have a problem with using socket.io in my application.
I use Next.js, Express.js, socket.io, socket.io-client
When I run Next.js server and Express server then access the page, socket is immediately connected. But when I post to /webhook/notify from other server socket.emit("notify", req.body); does not work. But when I reload the backend server, somehow it works for no reason.
Below are my codes
Frontend side
const socket = io.connect("http://127.0.0.1:3000", { cors: true }); //backend server
socket.on("connection", async (data) => { // it works
try {
console.log(data);
} catch (err) {
console.error(err.response);
}
});
socket.on("notify", async (notify) => { // it does not works while I reload backend server
try {
console.log(notify);
} catch (err) {
console.error(err.response);
}
});
Backend side
index.js
const app = express();
const PORT = process.env.PORT || 3000;
app.use(cors({ origin: "http://127.0.0.1:3060" }));
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
const Socket = require("./socket");
const server = app.listen(PORT, function () {
return console.log("Backend server listening on port" + PORT);
});
Socket(server, app);
socket.js
const Socket = require("socket.io");
const axios = require("axios");
module.exports = (server, app) => {
const io = Socket(server, {
cors: {
origin: "*",
},
});
io.on("connection", (socket) => {
console.log("socket is connected");
app.post("/webhook/notify", (req, res, next) => {
try {
socket.emit("notify", req.body);
} catch (err) {
console.error(err.response);
return next(err);
}
});
socket.on("disconnect", () => {
console.log("disconnected");
});
});
};
When ever I run my server locally it works perfectly
But once I upload it to vercel I get errors like polling-xhr.js:202 GET https://giphy-chat-server.vercel.app/socket.io/?EIO=4&transport=polling&t=NQ03j3c&sid=H_PHDh9-4UKRVGTVAAAC 400
And WebSocket connection to 'wss://giphy-chat-server.vercel.app/socket.io/?EIO=4&transport=websocket&sid=k-Sex1ZKmrQQFoSKAAAA' failed: Error during WebSocket handshake: Unexpected response code: 400
I have tried so many solutions but none is working... I can't just figure out the problem. I would be glad if Its answered. Thank you
const express = require("express");
const app = express();
const http = require("http");
const path = require("path");
var server = http.createServer(app);
const io = require("socket.io")(server, {
cors: {
origin: "*",
credentials: true,
methods: ["GET", "POST"],
},
});
const { MONGODB_URI } = require("./config");
const port = process.env.PORT || 8000;
const Message = require("./message_model");
const mongoose = require("mongoose");
mongoose
.connect(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
})
.then((result) => {
server.listen(port, () => {
console.log(`Listening on port ${port}...`);
});
})
.catch((err) => {
console.log(err);
});
app.use(express.static(path.join(__dirname, "..", "client", "build")));
const users = [];
io.on("connection", (socket) => {
users.push({ id: socket.id });
io.emit("users", { users: users });
Message.find()
.sort({ createdAt: -1 })
.limit(10)
.exec((err, messages) => {
if (err) return console.error(err);
socket.emit("init", messages);
});
socket.on("message", (msg) => {
const message = new Message({
content: msg.content,
name: msg.name,
});
message.save((err) => {
if (err) return console.error(err);
});
socket.broadcast.emit("push", msg);
});
socket.on("disconnect", (reason) => {
let index = -1;
for (let i = 0; i < users.length; i++) {
const user = users[i];
if (user.id === socket.id) {
index = i;
}
}
if (index !== -1) {
users.splice(index, 1);
}
io.emit("users", { users: users });
});
});
app.get("/", (req, res) => {
res.send("Giphy Chat Server is running successfully");
});
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
next();
});
I think this will be due to Vercel's serverless functions having a maximum execution timeout, so they can't maintain a websocket connection. In order to use Websockets with Vercel you'll need to use a third party service to handle your websocket connections for you. Something like Ably or Pusher, or PubNub.
I just wrote up a demo of next + ably if it would be helpful - https://github.com/ably-labs/NextJS-chat-app
I have create a simple express api to handle JSON data on my webapp.
Even if the app is on the same server, the response times are always on 100ms range, the actual data fetching is under 5ms;
Here is the data fetching zone :
export function getData(params) {
return new Promise((resolve, reject) => {
if (!params.take || params.take > 30 && isBrowser) {
params.take = 30;
}
console.time("API QUERY Execute");
{Data Fetching Goes here}
console.timeEnd("API QUERY Execute");
});
}
That method takes under 5 ms to complete from console.time.
Here is the express route config
app.route('/api/data').get((req, res) => {
getData(req.query)
.then((data) => {
res.json(data);
}).catch((err) => {
res.status(400);
res.send(err.message);
});
});
The actual Express App :
export default (parameters) => {
const app = Express();
const server = require('http').Server(app);
let io;
let redisCaching;
if (process.env.ENABLE_API === 'true') {
const Mongoose = require('mongoose');
const Redis = require('socket.io-redis');
Mongoose.connect(config.server.mongodb.url, config.server.mongodb.options);
Mongoose.connection.on('connected', () => {
console.log('==> Connected ', config.server.mongodb.url);
});
io = require('socket.io')(server);
io.sockets.on('connection', (socket) => {
console.log('==> Socket Connect', socket.handshake.headers.referer);
});
io.adapter(Redis({ host: 'localhost', port: 6379 }));
redisCaching = require('../../redis/redisCaching').redisCaching;
redisCaching.configure(6379, config.server.hostname);
}
if (process.env.CORS === 'true') {
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
}
app.route('/api/data').get((req, res) => {
getArticles(req.query)
.then((data) => {
res.json(data);
}).catch((err) => {
res.status(400);
res.send(err.message);
});
});
app.listen(process.env.PORT, () => {
console.log(`App listening on port ${process.env.PORT}`);
});
};
When using tools like pingdom, it showcases 100MS