Nodejs websocket 中的 cookie问题

Nodejs websocket 中的 cookie问题

同样的一份代码

var ws  = new WebSocket('ws://' + window.location.host + window.location.pathname);

chrome的header 无cookie

firfox的header 有cookie

为什么chrome ws请求header中没有cookie呢,有牛人能给我解答下么? 如何才能让chrome ws请求header中有cookie呢??

chrome中的header信息

GET ws://localhost:4567/games/matching-game/1 HTTP/1.1
Pragma: no-cache
Origin: http://localhost:4567
Host: localhost:4567
Sec-WebSocket-Key: 9NJMQbfnt2FSN2b2MkQ9cQ==
Upgrade: websocket
Sec-WebSocket-Extensions: x-webkit-deflate-frame
Cache-Control: no-cache
Connection: Upgrade
Sec-WebSocket-Version: 13

firefox中的header

GET /games/matching-game/1 HTTP/1.1
Host: localhost:4567
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:19.0) Gecko/20100101 Firefox/19.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://localhost:4567
Sec-WebSocket-Key: iTKGrDte+JmWeHmpHnFCpQ==
Cookie: rack.session=BAh7CUkiD3Nlc3Npb25faWQGOgZFRiJFODNiOTA0NmJmZDcwNDM0NjVlYjNl%0AMGU3YThiNjU1OGM1ODkxZmYwYWVjOGFhNDUwOGVlN2QxMTdjOGRlMDEzMEki%0ADXRyYWNraW5nBjsARnsISSIUSFRUUF9VU0VSX0FHRU5UBjsARiItNTA1OTFk%0AZWE0YTk3MGM2ZGM2ODhhNzEzZTFlNWUyZWRlMzEzYzA3NUkiGUhUVFBfQUND%0ARVBUX0VOQ09ESU5HBjsARiItYTBiZmM4NzZkNjhmZTdhZWE3MDBkYTVlYTg5%0AMjVhYmFjNmYyZjc5NEkiGUhUVFBfQUNDRVBUX0xBTkdVQUdFBjsARiItNTBj%0AYTM5YWY5NDU1ZTM1NmY2ZTlkOTRjZjU4NzE4ZTQzNzdhZjI5NEkiCWNzcmYG%0AOwBGIkU1Yzk1ZTQ5NTlhN2YwNjVhZDE2YTA1ZWYyMjFkMWY0ODNjMzc1Yzlh%0ANWQxZDQ4NmFhMThhYmRjYjA5ZDE1OTRlSSIMdXNlcl9pZAY7AEZpBg%3D%3D%0A--8122297af5825b47cfae2bf8f30342551dfba2a4
Connection: keep-alive, Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

8 回复

Node.js WebSocket 中的 Cookie 问题

在使用 WebSocket 连接时,不同浏览器对 Cookie 的处理方式可能会有所不同。例如,Chrome 和 Firefox 在处理 WebSocket 请求时的行为就存在差异。

问题描述

在同一份代码中:

var ws = new WebSocket('ws://' + window.location.host + window.location.pathname);
  • Chrome 的 WebSocket 请求头中没有 Cookie。
  • Firefox 的 WebSocket 请求头中有 Cookie。

原因分析

这是因为 WebSocket 协议本身并不直接携带 HTTP Cookies。当 WebSocket 连接建立时,浏览器会根据当前页面的 Cookie 状态决定是否将 Cookie 发送到 WebSocket 服务器。这取决于浏览器的实现细节以及安全策略。

解决方案

要确保 WebSocket 请求包含 Cookie,可以采取以下几种方法:

  1. 手动设置 Cookie 可以通过 JavaScript 手动将 Cookie 设置到 WebSocket 的请求头中。但需要注意的是,这种方式依赖于浏览器的支持。

    const socket = new WebSocket('ws://' + window.location.host + window.location.pathname);
    
    // 获取当前页面的 Cookie
    const cookies = document.cookie.split(';').reduce((acc, cookie) => {
        const [name, value] = cookie.trim().split('=');
        acc[name] = value;
        return acc;
    }, {});
    
    // 设置自定义 Header
    socket.onopen = () => {
        socket.send(JSON.stringify({
            type: 'set-cookie',
            data: cookies
        }));
    };
    
  2. 使用带有 Cookie 的 HTTP 请求 先通过 HTTP 请求获取 Cookie,然后再通过 WebSocket 连接发送 Cookie。

    fetch('http://localhost:4567/', {
        credentials: 'include'
    }).then(response => {
        if (response.ok) {
            return response.text();
        }
    }).then(data => {
        var ws = new WebSocket('ws://' + window.location.host + window.location.pathname);
        ws.onopen = () => {
            ws.send(JSON.stringify({
                type: 'set-cookie',
                data: document.cookie
            }));
        };
    });
    
  3. 服务器端处理 如果你有权限修改服务器端代码,可以在 WebSocket 握手过程中从 HTTP 请求头中提取 Cookie 并将其传递给 WebSocket 连接。

    const WebSocket = require('ws');
    const express = require('express');
    const app = express();
    
    app.use(express.json());
    app.use((req, res, next) => {
        res.setHeader('Access-Control-Allow-Credentials', 'true');
        res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4567');
        next();
    });
    
    app.get('/', (req, res) => {
        res.send('Hello World!');
        res.cookie('test', 'value', { httpOnly: false });
    });
    
    const wss = new WebSocket.Server({ server: app.server });
    
    wss.on('connection', (ws, req) => {
        const cookies = req.headers.cookie;
        console.log(cookies); // 输出 Cookie
        ws.send(JSON.stringify({
            type: 'cookie-received',
            data: cookies
        }));
    });
    
    app.listen(4567, () => {
        console.log('Server is running on port 4567');
    });
    

以上方法可以帮助你在 Chrome 浏览器中确保 WebSocket 请求包含 Cookie。希望这些示例代码和解释对你有所帮助!


没有人能给解释下么?

你服务端用的什么库?跟踪查看下请求信息

既然建立了socket连接,只要不断开,双方就可以互发数据。想要cookie只要服务端告诉客户端,我需要cookie,客户端send一下document.cookie,服务器就收到了。也许服务器不需要cookie呢。那firefox不是白发了?

继续说两句,cookie和session是为了解决http这种无状态的协议而产生的。socket一直保持连接,不需要cookie这种东西。换个思路,cookie只能保存64K的内容。而HTML5本地存储可以保存1M-5M的内容。如果服务器需要,也可以通过socket把本地存储的内容发送到服务器,发挥更多作用。

我也这样觉得, 只有想要 ws 共享原有的 cookie 登陆信息时才会两个弄一起 一般用的时候单纯用 ws 就能保证登录功能了

我想知道connection 绑定登录用户的问题解决了吗,我现在也要解决这个问题。

Chrome 和 Firefox 在处理 WebSocket 连接时对 Cookie 的处理方式不同。默认情况下,浏览器不会将 HTTP Cookie 自动发送到 WebSocket 连接中。为了在 WebSocket 请求中包含 Cookie,需要显式地设置。

示例代码

假设你使用的是 ws 模块来创建 WebSocket 客户端,你可以通过自定义握手过程来传递 Cookie。

客户端代码

const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:4567/games/matching-game/1', {
    headers: {
        'Cookie': 'rack.session=BAh7CUkiD3Nlc3Npb25faWQGOgZFRiJFODNiOTA0NmJmZDcwNDM0NjVlYjNl%0AMGU3YThiNjU1OGM1ODkxZmYwYWVjOGFhNDUwOGVlN2QxMTdjOGRlMDEzMEki%0ADXRyYWNraW5nBjsARnsISSIUSFRUUF9VU0VSX0FHRU5UBjsARiItNTA1OTFk%0AZWE0YTk3MGM2ZGM2ODhhNzEzZTFlNWUyZWRlMzEzYzA3NUkiGUhUVFBfQUND%0ARVBUX0VOQ09ESU5HBjsARiItYTBiZmM4NzZkNjhmZTdhZWE3MDBkYTVlYTg5%0AMjVhYmFjNmYyZjc5NEkiGUhUVFBfQUNDRVBUX0xBTkdVQUdFBjsARiItNTBj%0AYTM5YWY5NDU1ZTM1NmY2ZTlkOTRjZjU4NzE4ZTQzNzdhZjI5NEkiCWNzcmYG%0AOwBGIkU1Yzk1ZTQ5NTlhN2YwNjVhZDE2YTA1ZWYyMjFkMWY0ODNjMzc1Yzlh%0ANWQxZDQ4NmFhMThhYmRjYjA5ZDE1OTRlSSIMdXNlcl9pZAY7AEZpBg%3D%3D%0A--8122297af5825b47cfae2bf8f30342551dfba2a4'
    }
});

ws.on('open', function open() {
    console.log('Connected');
});

ws.on('message', function incoming(message) {
    console.log('received: %s', message);
});

服务器端代码

服务器端需要能够接收并处理这些 Cookie。这里以一个简单的 Node.js WebSocket 服务器为例:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 4567 });

wss.on('connection', function connection(ws, req) {
    console.log('headers:', req.headers);
    const cookies = req.headers.cookie;
    if (cookies) {
        console.log('Cookies received:', cookies);
    } else {
        console.log('No cookies received');
    }

    ws.on('message', function incoming(message) {
        console.log('received: %s', message);
    });
});

解释

  1. 客户端:在连接 WebSocket 时,通过设置 headers 属性中的 Cookie 来显式传递 Cookie。
  2. 服务器端:通过 req.headers 获取请求头中的 Cookie,并进行处理。

这种方式可以确保在 Chrome 和 Firefox 中都能正确地传递 Cookie。

回到顶部