Несоответствие заголовка Web-сокета Sec-WebSocket-Accept между клиентом ReactJS и сервером Node.js - PullRequest
0 голосов
/ 16 марта 2019

Я пишу приложение с использованием WebSockets с клиентом React на порту 8080 (запускается с использованием Webpack devServer) и Node-сервером и сокетами на порту 5000. Однако первоначальное рукопожатие всегда завершается с ошибкой: WebSocket connection to 'ws://localhost:5000/' failed: Error during WebSocket handshake: Incorrect 'Sec-WebSocket-Accept' header value

Чтобы убедиться, что я проверяю запрос и ответ приложения React с помощью Chrome devtools, я вижу следующее: enter image description here

Находясь на моем Node-сервере, я зарегистрировалsec-websocket-accept заголовок ключа подтверждения, а также заголовки для моего ответа, и получил следующее:

enter image description here

Похоже, что действительно,ключи не совпадают.На самом деле они не похожи на одни и те же клавиши.Есть ли что-то среднее между клиентом React и сервером Node (например, сервер разработчика Webpack, который я использую для React), которое их меняет?

Мой код 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
            });
        }
    }

Мой узел.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 голосов
/ 23 марта 2019

Для всех, кому интересно, виновниками проблемы, в моем случае, были дополнительные новые строки и возвраты, которые я добавил после записи своих заголовков на моем сервере Node.js. Вынимаем их и делаем:

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

вместо:

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

решил для меня несоответствие рукопожатия.

0 голосов
/ 17 марта 2019

Правильный хэш Accept для ключа 'S1cb73xifMvqiIpMjvBabg==' равен 'R35dUOuC/ldiVp1ZTchRsiHUnvo='.

Ваша функция generateValue() вычисляет неверный хеш, поскольку в строке GUID содержится неправильный символ '258EAFA5-E914–47DA-95CA-C5AB0DC85B11'. Если вы посмотрите очень внимательно, вы увидите, что вторая черта в «... 14–47 ...» отличается от других черточек. Это должен быть простой ASCII-тире или дефис с кодом символа 45, но на самом деле это Unicode en-dash с кодом символа 8211. Этот другой код символа отбрасывает вычисления.

Исправление этого символа сделает ваш клиент WebSocket намного счастливее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...