Решение проблем
Upgrade не проходит
| Симптом | Причина и решение |
|---|---|
| HTTP 400 | Запрос не является WebSocket upgrade. Проверьте схему URL клиента (ws:///wss://) и промежуточные прокси. |
| HTTP 403 | Origin страницы отсутствует в WebSocketOptions.AllowedOrigins. |
| HTTP 500 или другая ошибка сервера | Аутентификатор выбросил исключение во время upgrade; DarkWS 4.x это исключение не перехватывает. Проверьте лог ошибок сервера и возвращайте null для недействительных токенов вместо выбрасывания исключения. |
| HTTP 404 или upgrade так и не завершается | UseWebSockets() отсутствует или стоит после MapDarkWs, либо обратный прокси не передаёт заголовки Upgrade/Connection. |
| .NET-клиент перестаёт повторять попытки после 401/403 | Ошибки аутентификации постоянны. Исправьте учётные данные и вызовите ConnectAsync. |
За nginx передавайте заголовки upgrade и увеличьте таймаут чтения так, чтобы он превышал интервал heartbeat:
location /ws {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 120s;
}
Запросы завершаются ошибкой
| Ошибка | Причина и решение |
|---|---|
darkws:error:invalid-action | Имя не в формате handler:action, или сборка обработчика не зарегистрирована. |
darkws:error:authorization-required | У соединения нет аутентифицированной сессии. Сначала пройдите аутентификацию или пометьте действие [AllowAnonymous]. В браузере аутентифицируйте каждый новый сокет: передавайте токен через query или вызывайте authenticate() при каждом open. |
darkws:error:invalid-request | В запросе нет action или используется зарезервированный id, либо payload отсутствует для non-nullable параметра или имеет неверный тип. Сверьте имена JSON-свойств с политикой именования сервера. |
darkws:error:request-failed | Обработчик выбросил непредвиденное исключение. Исключение есть в логе сервера. |
| Таймаут без ответа | Обработчик медленный, или сокет полуоткрыт. Сервер также не отвечает, если сообщение не является JSON или не содержит строкового id, либо если обработчик вернул null или результат, который не удаётся сериализовать (в логе сервера есть предупреждение). Проверьте requestTimeout и настройки heartbeat. |
Соединения обрываются
| Код закрытия или симптом | Причина и решение |
|---|---|
| 1009 | Сообщение превысило MaxMessageSizeBytes (сервер) или MaxMessageSizeBytes (.NET-клиент). Отправляйте меньше или увеличьте лимит. |
| 1003 от .NET-клиента | Сервер отправил бинарный фрейм. |
| На .NET 8 простаивающие соединения закрываются примерно через 2 минуты | Клиент не отправляет трафик. Клиенты DarkWS отправляют ping каждые 30 секунд; собственные клиенты должны отправлять ping. |
| .NET-клиент сообщает, что сервер не подтвердил heartbeat, и переподключается | pong не пришёл в пределах PongTimeout. Прокси может отбрасывать текстовые фреймы, или соединение находится на пределе числа запросов, и сервер перестал читать. |
| Соединения закрываются во время деплоя | При остановке обработчики отменяются, а сокеты закрываются в пределах ShutdownTimeout. Клиенты переподключаются автоматически. |
Рассылки не доходят
- Сессия получателя не содержит группу. Группы читаются при подключении и повторной
аутентификации; после их изменения вызовите
ConnectionStorage.Add(connection). - При нескольких инстансах Redis не настроен, инстансы используют разные имена каналов, или инстанс был отключён от Redis в момент публикации сообщения.
- В браузере
action, с которым сравнивает ваш обработчикmessage, отличается регистром; имена действий чувствительны к регистру. - В .NET типизированная подписка
On<T>требуетdata; для рассылок без данных используйтеOn(action, () => …). Рассылка со значением null тоже приходит безdata.
Сессии выглядят неправильно
HandlerBase.Sessionвыбрасывает исключение для анонимных соединений. Для проверки на null используйтеConnection.Session.HandlerBase<TSession>.Sessionвыбрасывает исключение, если сессия не являетсяTSession, например когда всё ещё активен аутентификатор ASP.NET по умолчанию. ЗарегистрируйтеAddAuthenticator<TAuthenticator, TSession>().- После неудачной
auth:сессия очищается. - После переподключения серверная сессия новая. Браузерный клиент восстанавливает её
только через
queryдля upgrade или повторный вызовauthenticate(); .NET-клиент — только черезAuthenticationTokenProvider.
Ошибки при запуске
InvalidOperationException при запуске указывает обработчик, метод и причину.
Частые причины:
[Authorize]или атрибут политики на обработчике или действии; см. Обработчики и действия.- Действие, которое не является публичным методом экземпляра, возвращает что-то кроме
IResponseилиTask<IResponse>, имеет более одного параметра или является generic. - Два действия с одинаковым именем
handler:action. - Повторный вызов
AddDarkWs().
OptionsValidationException означает, что значение параметра вне допустимого
диапазона, например нулевой таймаут.