Решение проблем с подключением
Общие/известные проблемы:
Проблема: сокет не может подключиться
Возможные объяснения:
- Вы пытаетесь подключиться к простому серверу WebSocket
- Сервер недоступен
- Клиент несовместим с версией сервера
- Сервер не отправляет необходимые заголовки CORS
- Вы не включили "липкие сессии" (в конфигурации с несколькими серверами)
Вы пытаетесь подключиться к простому серверу WebSocket
Как объясняется в разделе "Что Socket.IO не реализует", клиент Socket.IO не является реализацией WebSocket и, следовательно, не сможет установить соединение с сервером WebSocket, даже с transports: ["websocket"].
const socket = io("ws://echo.websocket.org", {
transports: ["websocket"]
});
Сервер недоступен
Убедитесь, что сервер Socket.IO доступен по указанному URL. Вы можете проверить это с помощью:
curl "<the server URL>/socket.io/?EIO=4&transport=polling"
Результат должен быть примерно таким:
0{"sid":"Lbo5JLzTotvW3g2LAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000}
Если это не так, проверьте, что сервер Socket.IO запущен и нет никаких препятствий для подключения.
Клиент несовместим с версией сервера
Вот таблица совместимости для клиента JS:
| Версия JS клиента | Версия сервера Socket.IO | |||
|---|---|---|---|---|
| 1.x | 2.x | 3.x | 4.x | |
| 1.x | ДА | НЕТ | НЕТ | НЕТ |
| 2.x | НЕТ | ДА | ДА1 | ДА1 |
| 3.x | НЕТ | НЕТ | ДА | ДА |
| 4.x | НЕТ | НЕТ | ДА | ДА |
[1] Да, при allowEIO3: true
Вот таблица совместимости для клиента Java:
| Версия Java клиента | Версия сервера Socket.IO | ||
|---|---|---|---|
| 2.x | 3.x | 4.x | |
| 1.x | ДА | ДА1 | ДА1 |
| 2.x | НЕТ | ДА | ДА |
[1] Да, при allowEIO3: true
Вот таблица совместимости для клиента Swift:
| Версия Swift клиента | Версия сервера Socket.IO | ||
|---|---|---|---|
| 2.x | 3.x | 4.x | |
| v15.x | ДА | ДА1 | ДА2 |
| v16.x | ДА3 | ДА | ДА |
[1] Да, при allowEIO3: true (сервер) и .connectParams(["EIO": "3"]) (клиент):
SocketManager(socketURL: URL(string:"http://localhost:8087/")!, config: [.connectParams(["EIO": "3"])])
[2] Да, при allowEIO3: true (сервер)
[3] Да, при .version(.two) (клиент):
SocketManager(socketURL: URL(string:"http://localhost:8087/")!, config: [.version(.two)])
Сервер не отправляет необходимые заголовки CORS
Если вы видите следующую ошибку в консоли:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ...
Это, вероятно, означает, что:
- вы не правильно подключаетесь к серверу Socket.IO (см. выше)
- вы не включили Cross-Origin Resource Sharing (CORS) на стороне сервера.
См. документацию здесь.
Вы не включили "липкие сессии" (в конфигурации с несколькими серверами)
При масштабировании до нескольких серверов Socket.IO необходимо убедиться, что все запросы от данного сеанса Socket.IO попадают на один и тот же сервер Socket.IO. Объяснение можно найти здесь.
Если этого не сделать, вы получите HTTP 400 ответы с кодом: {"code":1,"message":"Session ID unknown"}
См. документацию здесь.
Проблема: сокет отключается
Прежде всего, обратите внимание, что отключения — распространённое и ожидаемое явление, даже при стабильном интернет-соединении:
- любой элемент между пользователем и сервером Socket.IO может временно выйти из строя или перезапуститься
- сам сервер может быть остановлен в рамках политики автоматического масштабирования
- пользователь может потерять соединение или переключиться с Wi-Fi на 4G, если использует мобильный браузер
- сам браузер может заблокировать неактивную вкладку
При этом клиент Socket.IO всегда будет пытаться повторно подключиться, если ему не указано иное здесь.
Возможные объяснения отключения:
- Вкладка браузера была свёрнута, и механизм heartbeat не сработал
- Клиент несовместим с версией сервера
- Вы пытаетесь отправить очень большой объём данных
Вкладка браузера была свёрнута, и механизм heartbeat не сработал
Когда вкладка браузера не активна, некоторые браузеры (например, Chrome) ограничивают таймеры JavaScript, что может привести к отключению из-за таймаута heartbeat в Socket.IO v2, поскольку механизм heartbeat полагался на функцию setTimeout на стороне клиента.
В качестве обходного решения можно увеличить значение pingTimeout на стороне сервера:
const io = new Server({
pingTimeout: 60000
});
Обратите внимание, что обновление до Socket.IO v4 (по крайней мере socket.io-client@4.1.3, из-за этой причины) должно предотвратить подобные проблемы, поскольку механизм heartbeat был изменён (теперь сервер отправляет пакеты PING).
Клиент несовместим с версией сервера
Поскольку формат пакетов, отправляемых через транспорт WebSocket, аналогичен в v2 и v3/v4, вы, возможно, сможете подключиться с несовместимым клиентом (см. выше), но подключение будет закрыто через определённое время.
Таким образом, если у вас происходит регулярное отключение через 30 секунд (что было суммой значений pingTimeout и pingInterval в Socket.IO v2), это, безусловно, связано с несовместимостью версий.
Вы пытаетесь отправить очень большой объём данных
Если вы отключаетесь при отправке очень большого объёма данных, это может означать, что вы достигли значения maxHttpBufferSize, которое по умолчанию равно 1 МБ. Настройте его в соответствии с вашими потребностями:
const io = require("socket.io")(httpServer, {
maxHttpBufferSize: 1e8
});
Очень большой объём данных, который загружается дольше, чем значение параметра pingTimeout, также может вызвать отключение (поскольку механизм heartbeat завершается неудачно во время загрузки). Настройте его в соответствии с вашими потребностями:
const io = require("socket.io")(httpServer, {
pingTimeout: 60000
});
Проблема: сокет застрял в HTTP-долговом опросе
В большинстве случаев вы должны увидеть что-то вроде этого:
- установление соединения Engine.IO (содержит идентификатор сеанса — здесь,
zBjrh...AAAK— используемый в последующих запросах) - запрос установления соединения Socket.IO (содержит значение параметра
auth) - ответ на запрос установления соединения Socket.IO (содержит Socket#id)
- соединение WebSocket
- первый запрос HTTP-долгового опроса, который закрывается после установления соединения WebSocket
Если вы не видите ответа HTTP 101 Switching Protocols для 4-го запроса, это означает, что что-то между сервером и вашим браузером препятствует подключению WebSocket.
Обратите внимание, что это не обязательно блокирует процесс, поскольку подключение всё ещё устанавливается с помощью HTTP-долгового опроса, но это менее эффективный способ.
Вы можете получить имя текущего транспорта с помощью:
Клиентская сторона
socket.on("connect", () => {
const transport = socket.io.engine.transport.name; // in most cases, "polling"
socket.io.engine.on("upgrade", () => {
const upgradedTransport = socket.io.engine.transport.name; // in most cases, "websocket"
});
});
Серверная сторона
io.on("connection", (socket) => {
const transport = socket.conn.transport.name; // in most cases, "polling"
socket.conn.on("upgrade", () => {
const upgradedTransport = socket.conn.transport.name; // in most cases, "websocket"
});
});
Возможные причины:
Прокси перед вашими серверами не принимает подключение WebSocket
См. документацию здесь.
© 2014–2021 Automattic
Licensed under the MIT License.
https://socket.io/docs/v4/troubleshooting-connection-issues