WebSockets

WebSockets and the Upgrade Handshake

A WebSocket connection starts as an ordinary HTTP GET carrying Upgrade: websocket and a random Sec-WebSocket-Key. The server answers 101 Switching Protocols with Sec-WebSocket-Accept, the base64 SHA-1 of that key plus a fixed GUID, and the TCP connection then carries RFC 6455 frames instead of requests. Networking and HTTP works at that level and Front-End Web Development covers the browser WebSocket object; what matters here is that the handshake does not land in your middleware stack. Node emits upgrade on the http.Server, not request, and Express 24,430 is only a request listener, so every app.use() you wrote — helmet 10,736 , CORS, sessions, the rate limiter — is skipped.

An upgrade handshake reaches the server, not the middleware stackJavaScript
const GUID = '258EAFA5-E914-47DA-95CA-5AB0DC85B11F';   // from RFC 6455
const app = express();
app.use((req, _res, next) => { console.log('middleware saw', req.method, req.url); next(); });
app.get('/books', (_req, res) => res.json([]));
const server = http.createServer(app);
server.on('upgrade', (req, socket) => {                // Express never sees this request
  console.log('upgrade to', req.url, '| version', req.headers['sec-websocket-version']);
  const key = req.headers['sec-websocket-key'];
  const accept = createHash('sha1').update(key + GUID).digest('base64');
  socket.write('HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\n' +
    `Connection: Upgrade\r\nSec-WebSocket-Accept: ${accept}\r\n\r\n`);
  socket.end();                                        // a real server would frame data here
});
server.listen(4138);

A raw net client (TCP Sockets with net) sends the handshake; the script then makes one plain request:

Output of 77
upgrade to /live | version 13
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: AVrTC1h4byEIE4gXcWN0V/uDFOA=
middleware saw GET /books
plain GET: 200

The middleware logged the later GET /books and never the upgrade. Three consequences explain most real-time bugs in Express apps: the origin check must be repeated for sockets (Socket.IO on an Express Server), the session cookie read from socket.handshake by hand (Rooms and Auth), and the reverse proxy told to pass the handshake on — nginx 75 uses HTTP/1.0 upstream and strips hop-by-hop headers until you set proxy_http_version 1.1 and forward Upgrade and Connection (Running Behind nginx). Write frame handling yourself only to learn it: ws 22,807 (https://github.com/websockets/ws 22,807 ) (8.21.3, MIT) is the minimal production choice, and what Socket.IO 24,482 uses internally.