express
express copied to clipboard
WebSocket GET handshake (upgrade) routing
I don't meam an "integrated WebSocket server" but the possibility of performing express routing for WebSocket handshake requests.
Node httpServer
emits an "upgrade" event for HTTP GET requests including a "Upgrade" header. Express may provide a new "method" called "websocket" for handling them (if the "Upgrade" header has value "websocket"), so the GET request may be processed as any other HTTP verb:
var app = express();
app.websocket('/websocket/:service', function(req, res, next) {
[...]
});
In this way, Cookies present in the HTTP request may be checked using express middlewares (for example).
Perhaps, but Express is not a HTTP server, it is only a function. You just pass an Express app yo the requestListener osf whatever HTTP server module you choose to use.
All an app is is app(req, res, next). You can even typeof on your app variable. Because of this, Express has no way to actually listen to any events on the HTTP server.
As for using Express middleware with websockets, this is already possible without any effort from express. Many many people already do this today, especially with express-session.
I'm not dismissing this (or I would have closed the issue), but if you or someone could put together a PR that is even just a WIP towards this against the 5.x branch, that would have the best chance of getting in :)
FYI I don't think it's necessary to listen to the event, that is just a convenience for other libraries (i.e. socket.io
). We just need to check if the Upgrade:
header is present and act accordingly.
Please make a PR :)
IMHO this is not so easy. AFAIK the httpServer
will emit upgrade
upon receipt of a GET request with header "Upgrade", and it is in that event where existing WS libraries (such as ws
or websocket-node
) react to perform the handshake or notify the app. What I mean is that, at that point ("upgrade" event fired) the WS server as already control over the request. Express should keep the "upgrade" event until a middleware handles it. Otherwise it should be replied with 404 as usual, but for that something should listen for the "upgrade" event and invoke the app.handle()
method somehow...
Sure. The problem is I really don't use WebSockets, so I'm really looking for someone to offer a PR against the 5.x branch for this idea is all, otherwise if no on I going to make a PR, I may have to close this issue since it's not being acted on.
The PR can even be a WIP, as I said above. I'm just looking for code to demonstrate your idea.
+1 I'm currently using a custom handleUpgrade to do authentication before passing the request to https://github.com/websockets/ws/ but it would be nice to be able to use express middleware / routing. Not interested in using socket.io
Just wrote this module: https://github.com/olalonde/express-websocket
var http = require('http');
var ws = require('ws');
module.exports = function (app, wss) {
if (!wss) {
wss = new ws.Server({ noServer: true });
}
// https://github.com/websockets/ws/blob/master/lib/WebSocketServer.js#L77
return function (req, socket, upgradeHead) {
var res = new http.ServerResponse(req);
res.assignSocket(socket);
res.websocket = function (cb) {
var head = new Buffer(upgradeHead.length);
upgradeHead.copy(head);
wss.handleUpgrade(req, socket, head, function (client) {
//client.req = req; res.req
wss.emit('connection'+req.url, client);
wss.emit('connection', client);
cb(client);
});
};
return app(req, res);
};
};
Basically, it routes the request to an express app and exposes the res.websocket() method which starts the websocket connection.
There hasn't been much discussion in here for a month. Any thoughts on issuing a PR to discuss over? Otherwise, I may need to close this for becoming stale.
It'd be awesome to do something like the above that @olalonde has done, and I might be adopting his solution (if slightly modified). As it currently stands, it feels very strangely architectured IMHO.
edit: my solution:
let http = require('http')
let express = require('express')
let app = express()
let server = http.createServer(...)
// ... etc
server.on('upgrade', (req, socket) => {
let res = new http.ServerResponse(req)
res.assignSocket(socket)
res.on('finish', () => res.socket.destroy())
app(req, res)
})
// elsewhere
router.use('/', (req, res, next) => {
if (!req.headers ||
req.headers.upgrade === undefined ||
req.headers.upgrade.toLowerCase() !== 'websocket') return next()
wss.handleUpgrade(req, req.socket, undefined, (socket) => {
console.log('upgraded!')
socket.send('woo')
socket.close()
})
})
I just ran across this old thread. Perhaps the following library is relevant now? https://www.npmjs.com/package/express-ws