ReactJS客户端和Node.js服务器之间的Websocket'Sec-WebSocket-Accept'标头不匹配

时间:2019-03-16 01:19:58

标签: node.js reactjs sockets websocket

我正在使用WebSockets和端口8080上的React客户端(使用Webpack devServer运行)以及Node服务器和端口5000上的套接字使用WebSockets编写应用程序。但是,初始握手始终失败,并显示以下错误:WebSocket connection to 'ws://localhost:5000/' failed: Error during WebSocket handshake: Incorrect 'Sec-WebSocket-Accept' header value < / p>

为了确保这一点,我使用Chrome devtools检查了React应用程序的请求和响应,并查看以下内容: enter image description here

在Node服务器上,我记录了sec-websocket-accept标头接受密钥以及响应的标头,并得到了以下信息:

enter image description here

看起来确实如此,键不匹配。实际上,它们似乎根本不是相同的键。在React客户端和Node服务器之间(例如我用于React的Webpack devserver)之间是否有东西在改变它们?

我的React代码:

    componentDidMount(){
        this.socket = new WebSocket('ws://localhost:5000', ['json']);
        this.socket.onerror = err => {
            console.log(err)
        }
        this.socket.onmessage = e => {
            let res = JSON.parse(e.data);
            console.log(e, res);
            let copyArr = [...this.state.message]
            copyArr.push(res);

            this.setState({
                message: copyArr
            });
        }
    }

我的Node.js代码:

const server = http.createServer();

server.on('upgrade', (req, socket) => {

    if(req.headers['upgrade'] !== "websocket"){
        socket.end('HTTP/1.1 400 Bad Request');
        return;
    }

    const acceptKey = req.headers['sec-websocket-key'];
    const acceptHash = generateValue(acceptKey);

    console.log('accepkey', acceptKey, 'hash', acceptHash);

    const resHeaders = [ 'HTTP/1.1 101 Web Socket Protocol Handshake', 'Upgrade: WebSocket', 'Connection: Upgrade', `Sec-WebSocket-Accept: ${acceptHash}` ];

    console.log(resHeaders);

    let protocols = req.headers['sec-websocket-protocol'];
    protocols = !protocols ? [] : protocols.split(',').map(name => name.trim());

    if(protocols.includes('json')){
        console.log('json here');
        resHeaders.push(`Sec-WebSocket-Protocol: json`);
    }

    socket.write(resHeaders.join('\r\n') + '\r\n\r\n');
})

function generateValue(key){
    return crypto
      .createHash('sha1')
      .update(key + '258EAFA5-E914–47DA-95CA-C5AB0DC85B11', 'binary')
      .digest('base64');
}

2 个答案:

答案 0 :(得分:0)

'S1cb73xifMvqiIpMjvBabg=='键的正确“接受”哈希为'R35dUOuC/ldiVp1ZTchRsiHUnvo='

您的generateValue()函数计算出不正确的哈希值,因为它在GUID字符串'258EAFA5-E914–47DA-95CA-C5AB0DC85B11'中具有不正确的字符。如果仔细看,您会发现第二个破折号'... 14–47 ...'与其他破折号不同。它应该是字符代码为45的纯ASCII破折号或连字符,但实际上它是字符代码为8211的Unicode破折号。不同的字符代码会影响计算。

修正该字符将使您的WebSocket客户端更加快乐。

答案 1 :(得分:0)

对于任何想知道问题的人,导致问题的元凶,是我在Node.js服务器中编写标头后添加的额外的新行和返回值。带他们出去做:

socket.write(resHeaders.join('\r\n'));

代替:

socket.write(resHeaders.join('\r\n') + '\r\n\r\n');

为我解决了握手不匹配的情况。