Рукопожатие: HTTP Upgrade
WebSocket начинается как обычный HTTP-запрос — и в один момент превращается в постоянный канал.
Рукопожатие WebSocket — обмен одним HTTP-запросом и ответом, после которого соединение переключается (
Upgrade) с HTTP на протокол WebSocket поверх того же TCP-соединения.
Зачем начинать с HTTP
WebSocket мог бы использовать собственный порт и протокол с нуля, но тогда его блокировали бы корпоративные прокси и файрволы, заточенные под HTTP/80 и HTTPS/443. Поэтому WebSocket маскируется: открывается как обычный HTTP-запрос на тот же порт, проходит через инфраструктуру — и только потом «переобувается» в свой протокол. Это и есть рукопожатие.
Запрос на повышение
Браузер шлёт обычный GET, но с особыми заголовками:
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13Ключевое — Upgrade: websocket и Connection: Upgrade: «хочу переключить протокол». Sec-WebSocket-Key — случайная строка для проверки, что сервер действительно понимает WebSocket.
Ответ сервера
Если сервер согласен, он отвечает кодом 101 Switching Protocols:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=После этого ответа HTTP заканчивается, и по тому же TCP-соединению начинают ходить WebSocket-фреймы — в обе стороны.
Как работает под капотом
Поле Sec-WebSocket-Accept — не магия: сервер берёт присланный Sec-WebSocket-Key, дописывает к нему фиксированную строку-«соль» (GUID из стандарта), считает SHA-1 и кодирует в base64. Браузер делает то же самое и сверяет результат. Совпало — значит на той стороне настоящий WebSocket-сервер, а не случайный обработчик, машинально вернувший 101. Это защищает от ложных «апгрейдов» через кеширующие прокси.
Браузер Сервер | GET /chat (Upgrade) ----> | | <---- 101 Switching ------ | |======== канал открыт =======| | фрейм "привет" ---------> | | <--------- фрейм "ок" |
Частые ошибки
- Ждать код 200. Успешное рукопожатие — это 101, а не 200.
- Думать, что рукопожатие повторяется на каждое сообщение. Оно одно — в самом начале; дальше канал просто живёт.
- Игнорировать прокси. Некоторые старые прокси не пропускают Upgrade; для надёжности используют
wss://(через TLS), который прокси не вскрывают.
Итоги
- WebSocket-соединение открывается как HTTP-запрос с заголовками
Upgrade: websocketиConnection: Upgrade. - Сервер соглашается ответом 101 Switching Protocols.
Sec-WebSocket-Acceptподтверждает, что на той стороне настоящий WebSocket-сервер.- После рукопожатия по тому же TCP-каналу идут двусторонние фреймы.