[{"data":1,"prerenderedAt":17},["ShallowReactive",2],{"api:\u002Fapi\u002Fconfig:ru":3,"api:\u002Fapi\u002Fnotes\u002Fwebsocket-from-scratch:ru":8},{"email":4,"lang":5,"name":6,"role":7},"hello@ewsirdev.example","ru","Ewsirdev","Веб-разработчик: сайты, лендинги и сервисы на Go",{"slug":9,"lang":5,"title":10,"date":11,"summary":12,"project":13,"minutes":14,"body_md":15,"body_html":16},"websocket-from-scratch","WebSocket на стандартной библиотеке: что на самом деле происходит под new WebSocket()","2026-10-20","Зачем в realtime-rooms написан собственный слой RFC 6455, какие нарушения протокола он проверяет и почему для продакшена всё равно лучше взять библиотеку.","realtime-rooms",2,"Слой WebSocket в realtime-rooms (`internal\u002Fws`, около 530 строк) написан только на стандартной библиотеке. Цель была учебной: увидеть, что скрывается под `new WebSocket(...)`.\n\n## Рукопожатие\n\nЭто обычный GET с `Connection: Upgrade`, `Upgrade: websocket`, версией 13 и ключом в 16 байт (base64). Сервер отвечает 101 и `Sec-WebSocket-Accept`. Проверяется и Origin: тот же хост, значение из `ALLOWED_ORIGINS` или отсутствие заголовка у не браузерных клиентов, иначе 403.\n\n## Фреймы\n\nДлина кодируется в 7, 16 или 64 бита, и неминимальная кодировка отвергается. Клиентские фреймы обязаны быть замаскированы, серверные нет. Управляющие фреймы не длиннее 125 байт и не фрагментируются. Размер проверяется по заголовку до выделения памяти, поэтому огромный фрейм не раздувает процесс.\n\n## Что проверяют тесты\n\nПример рукопожатия из RFC, пример замаскированного фрейма, фрагментация с ping посередине и 12 видов нарушений протокола, для каждого из которых проверяется код close.\n\n## Честная оговорка\n\nДля продакшена обычно берут проверенную библиотеку: она прошла Autobahn Test Suite, умеет `permessage-deflate` и закрывает больше граничных случаев. Здесь Autobahn не запускался, расширения не поддерживаются. Это учебный слой, а не замена библиотеки.\n","\u003Cp>Слой WebSocket в realtime-rooms (\u003Ccode>internal\u002Fws\u003C\u002Fcode>, около 530 строк) написан только на стандартной библиотеке. Цель была учебной: увидеть, что скрывается под \u003Ccode>new WebSocket(...)\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2>Рукопожатие\u003C\u002Fh2>\n\u003Cp>Это обычный GET с \u003Ccode>Connection: Upgrade\u003C\u002Fcode>, \u003Ccode>Upgrade: websocket\u003C\u002Fcode>, версией 13 и ключом в 16 байт (base64). Сервер отвечает 101 и \u003Ccode>Sec-WebSocket-Accept\u003C\u002Fcode>. Проверяется и Origin: тот же хост, значение из \u003Ccode>ALLOWED_ORIGINS\u003C\u002Fcode> или отсутствие заголовка у не браузерных клиентов, иначе 403.\u003C\u002Fp>\n\u003Ch2>Фреймы\u003C\u002Fh2>\n\u003Cp>Длина кодируется в 7, 16 или 64 бита, и неминимальная кодировка отвергается. Клиентские фреймы обязаны быть замаскированы, серверные нет. Управляющие фреймы не длиннее 125 байт и не фрагментируются. Размер проверяется по заголовку до выделения памяти, поэтому огромный фрейм не раздувает процесс.\u003C\u002Fp>\n\u003Ch2>Что проверяют тесты\u003C\u002Fh2>\n\u003Cp>Пример рукопожатия из RFC, пример замаскированного фрейма, фрагментация с ping посередине и 12 видов нарушений протокола, для каждого из которых проверяется код close.\u003C\u002Fp>\n\u003Ch2>Честная оговорка\u003C\u002Fh2>\n\u003Cp>Для продакшена обычно берут проверенную библиотеку: она прошла Autobahn Test Suite, умеет \u003Ccode>permessage-deflate\u003C\u002Fcode> и закрывает больше граничных случаев. Здесь Autobahn не запускался, расширения не поддерживаются. Это учебный слой, а не замена библиотеки.\u003C\u002Fp>\n",1792697892639]