i want to use jsonwebtoken, but after i've tried implement it, it gives me this error:WebSocket is closed before the connection is established.
I cant see whats wrong with the code. im not able to do anything on the localhost as it looses connection all the time.
Client
chat.js
const socket = io({
extraheaders: {
token : sessionStorage
}
});
Server
app.js
io.use((socket, next) => {
const {token}= socket.handshake.auth.headers;
if (token && token ===sessionStorage){
return next();
}
next(new Error('Pls login again'))
.on('connection', function(socket) {
console.log(token)
// Connection now authenticated to receive further events
socket.on('message', function(message) {
io.emit('message', message);
console.log(socket.handshake.auth.headers)
});
[![Localstorage][1]][1]
[1]: https://i.stack.imgur.com/YewlR.png
Related
I've an application, which is built in axios, just PUT, POST, DELETE, GET in mind. which looks like this
getAPI = axios.create(.....)
....
getAPI.post('signup/', {email, password})
.then(res => {
/// return some res
})
.catch(err => {
/// some error is show if not succeed
})
}
and also goes or "post/", "logout/", "signup/" with different methods.
Later i found that, In order to make post actions realtime in client side , we need to use websocket. So i used socket.io .
I've already setup server and client.
In server socket connection like this
io.on('connection', socket => {
console.log('User is connected on socket');
socket.on('disconnect', () => console.log('disconnected'));
})
and in client connection i've searc tutorials and used contextAPI, and passed to allcomponents.
in my specific component, where i've user post and user post is shown i've put code like this
const {socket} = useContext(AuthContext);
useEffect(() => {
socket.on("connect", () => {
console.log("client connected")
})
return ()=> socket.disconnect()
})
Now how can i use those of axios request with catch errors but with socket.io. It seems very hard to me using socket.io integrating with axios . Although i need not to use socket on authentication. But i need to use it on "/post" request.
Posting from client to server was easy by that axios.POST.then().catch(), axios.GET .....
but i'm confused to integrate that axios things in socket in client .
Also in backend side , i've routes like these
router.get('/logout', logout)
router.post('/post/create', post)
with each handler like these
exports.postCreate = (req, res) => {
let post = new Post(req.body)
post.save((err, post) => {
if(err){
return res.status(400).json({error: "Error"})
}
return res.json(post)
})
}
but if i want to use socket.io, what should i do? I'm very confused by socket.io docs, not showing for handeling things.
If you have idea about these things,
please answer me Thank you for your answer
Socket.io keeps its connections alive. In order to handle errors. You will need to listen to events. For example:
Handling connection errors:
socket.on("connect_error", (error) => {
// ...
});
Handling disconnect errors:
socket.on("disconnect", (reason) => {
if (reason === "io server disconnect") {
// the disconnection was initiated by the server, you need to reconnect manually
socket.connect();
}
// else the socket will automatically try to reconnect
});
If you'd like to ensure that your server side handled your request and need confirmation you can use the optional 'ack' feature like this:
// client side
socket.emit("ferret", "tobi", (data) => {
console.log(data); // data will be "woot"
});
// server side:
io.on("connection", (socket) => {
socket.on("ferret", (name, fn) => {
fn("woot");
});
});
My client is not receiving the broadcast sent to the room. If I replace socket.to(roomName).emit('join', currentUser); with socket.emit('join', currentUser); the client receives the broadcast, but I'd like to use rooms here. Any help would be greatly appreciated.
app.js
// Game
app.get('/game', (req, res) => {
const cookies = req.cookies;
const currentUser = cookies['current_user'];
const roomName = cookies['room_name'];
if (roomName) {
res.render('pages/game', {
room: roomName
});
io.of('/game').on('connection', socket => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
socket.join(roomName);
socket.to(roomName).emit('join', currentUser);
});
} else {
res.redirect('/login');
}
});
game.ejs
const socket = io("/game");
socket.on('join', function(user) {
console.log(`${user} joined`);
});
Also, could I replace this:
if (roomName) {
// stuff
} else {
// other stuff
}
with this:
if (!roomName) {
// other stuff
return;
}
// stuff
According to the documentation, if you use socket.to('room').emit(...) instead of io.in('room').emit(...), it will be broadcasted to all sockets in the room except the sender. That's where your problem lies.
The reason socket.emit(...) works is because you're sending it directly and only to the sender.
This emit cheatsheet is quite useful to figure out which combinations of io/socket and to etc affect where messages get sent to.
The basic problem can be summarized as follows: When creating a Websocket server in Node using ws with the server option populated by an express server(as in this example), while using that same express server to handle the routing for NextJS (as in this example), the upgrade header seems to not be properly parsed.
Instead of the request being routed to the Websocket server, express sends back an HTTP 200 OK response.
I've searched high and low for an answer to this, it may be that I simply do not understand the problem. A possibly related question was brought up in an issue on NextJS's github. They recommend setting WebsocketPort and WebsocketProxyPort options in the local next.config.js, however I have tried this to no avail.
A minimal example of the relevant server code can be found below. You may find the full example here.
const express = require('express')
const next = require('next')
const SocketServer = require('ws').Server;
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
const wss = new SocketServer({ server });
wss.on('connection', function connection(ws, request) {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
wss.on('error', function (error) {
console.log(error);
});
setInterval(() => {
wss.clients.forEach((client) => {
client.send(new Date().toTimeString());
});
}, 1000);
}).catch(ex => {
console.error(ex.stack);
process.exit(1);
});
The expected result, of course, is a connection to the websocket server. Instead I receive the following error:
WebSocket connection to 'ws://localhost:3000/' failed: Error during WebSocket handshake: Unexpected response code: 200
Can anyone elucidate anything for me here?
Ok, after more digging I have solved the problem. Quite simply, the ws.Server object to which I was trying to feed the server = express() object is not strictly speaking an http server object. However, server.listen() returns such an http server object. On such an object we can listen for an 'upgrade' call, which we can pass to our ws.Server object's handleUpgrade() event listener, through which we can connect. I will be updating the examples that I linked in my question, but the relevant code is below:
app.prepare().then(() => {
const server = express()
server.all('*', (req, res) => {
return handle(req, res)
})
const wss = new SocketServer({ server });
wss.on('connection', function connection(ws, request) {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
wss.on('error', function (error) {
console.log(error);
});
let srv = server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
srv.on('upgrade', function(req, socket, head) {
wss.handleUpgrade(req, socket, head, function connected(ws) {
wss.emit('connection', ws, req);
})
});
I try to make an application that receives from a third part application UDP packets.
I try to create a server UDP in NodeJS, but now when I receive the data I don't know how can I show it in a browser windows.
I explain better...my application receives data via udp in real time, the server processes them and should show them real time on a web page.
This is my code for UDP server in NodeJS:
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('error', (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
});
server.on('message', (msg, rinfo) => {
console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
console.log(` messaggio ricevuto ${msg}`);
});
server.on('listening', () => {
const address = server.address();
console.log(`server listening ${address.address}:${address.port}`);
});
server.bind({
adress:'127.0.0.1',
port:'41234'
});
// server listening address :41234
Thanks a lot for the reply
welcome to SO!
You could do something like below...
// Open a connection
var socket = new WebSocket('ws://localhost:41234/');
// When a connection is made
socket.onopen = function() {
console.log('Opened connection 🎉');
// send data to the server
var json = JSON.stringify({ message: 'Hello 👋' });
socket.send(json);
}
// When data is received
socket.onmessage = function(event) {
console.log(event.data);
}
// A connection could not be made
socket.onerror = function(event) {
console.log(event);
}
// A connection was closed
socket.onclose = function(code, reason) {
console.log(code, reason);
}
// Close the connection when the window is closed
window.addEventListener('beforeunload', function() {
socket.close();
});
This link should give you more info : https://www.sitepoint.com/real-time-apps-websockets-server-sent-events/ (above snippet is taken from this link)
You need a web server to send data to browser.
This link https://socket.io/get-started/chat will help you create a webserver.
You could send the message received on UDP port to the websocket as below
server.on('message', (msg, rinfo) => {
socket.emit('sendData', msg);
});
I've been trying to resolve a really strange Socket.io bug.
If I open the page on the client while the server is running, it will fail to connect with the message:
universalModuleDefinition:3 WebSocket connection to
'ws://localhost:4000/socket.io/?EIO=3&transport=websocket&sid=f6LwPIDZubiPKE-TAAAA'
failed: Connection closed before receiving a handshake response
If I then restart the server, while leaving the page open, it connects without issue.
app.js
const app = express();
const server = require('http').Server(app);
require('./socket')(server);
// More code here
server.listen(app.get('port'))
socket.js
const io = require('socket.io');
const jackrabbit = require(`jackrabbit`);
const rabbit = jackrabbit(process.env.RABBIT_URI);
const exchange = rabbit.default();
function Socket (app) {
this.io = io(app);
this.io.on('connection', socket => {
socket.emit('sync');
socket.on('room', room => {
socket.join(room);
});
})
this.queue = exchange.queue({ name: 'worker.socket' });
this.queue.consume(this.onMessage.bind(this), { noAck: true });
}
Socket.prototype.onMessage = function (message) {
this.io.to(message.report).emit('photo', message.photo);
}
module.exports = function (app) {
return new Socket(app);
}
client
var socket = io.connect();
socket.on('connect', function () {
// This gets triggered every time (after the error above)
console.log('Connected');
// This is never logged by the server
socket.emit('room', value); // value set by template engine
});
socket.on('sync', function(){
// will not execute first time I connect, but if I restart
// the server, it runs no problem
alert('Synced with server');
})
socket.on('photo', function(data) {
// also will not be run the first time, but works if the
// server is restarted when the page is open
})
Edit:
I've tried rewriting it to
Initialise socket.io within app.js, then pass it to the socket controller
Run server.listen before requiring socket.js
Initialising the client after a timeout
Setting the transport method on the client strictly to websocket
None of these methods have worked
Found the solution to my problem (actually not an issue with any of the code I posted). I was using the compression middleware for Express, which appears to break socket.io. Solution was to add the following:
app.use((req, res, next) => {
// Disable compression for socket.io
if (req.originalUrl.indexOf('socket.io') > -1) {
return next();
}
compression()(req, res, next);
});