> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Отладка WebSocket

> Как выяснить, почему WebSocket-соединение Solana с OrbitFlare отклоняется, молчит или обрывается: ошибки рукопожатия, подписки без событий, отключение по простою и keepalive.

Большинство проблем с WebSocket делятся на три группы: соединение отклоняется, соединение устанавливается, но ничего не приходит, или оно какое-то время работает, а потом обрывается. Сначала определите, какой у вас случай.

## Начните с заведомо рабочей подписки

`slotSubscribe` срабатывает каждый слот, примерно пять раз в секунду, поэтому почти сразу видно, работает ли само соединение. Установите [wscat](https://github.com/websockets/wscat) командой `npm install -g wscat`, затем:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
wscat -c "wss://fra.rpc.orbitflare.com?api_key=$ORBITFLARE_LICENSE_KEY"
> {"jsonrpc":"2.0","id":1,"method":"slotSubscribe"}
```

Рабочее соединение отвечает идентификатором подписки, а затем потоком уведомлений:

```json theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
{"jsonrpc":"2.0","result":332807,"id":1}
{"jsonrpc":"2.0","method":"slotNotification","params":{"result":{"slot":459760339,"parent":459760338,"root":459760337},"subscription":332807}}
```

Если это работает, а ваша собственная подписка нет, проблема в подписке, а не в соединении. Переходите к разделу [Соединение есть, но обновлений нет](#соединение-есть-но-обновлений-нет).

## Соединение отклонено

Аутентификация происходит во время рукопожатия WebSocket. Если она не прошла, сервер отвечает на запрос upgrade обычной HTTP-ошибкой с JSON-телом вместо переключения протокола. Многие библиотеки WebSocket сообщают только «unexpected server response: 403» и отбрасывают тело, поэтому проверьте рукопожатие через curl, чтобы увидеть настоящую причину:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
curl -i --http1.1 \
  -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  "https://fra.rpc.orbitflare.com/?api_key=$ORBITFLARE_LICENSE_KEY"
```

`HTTP/1.1 101 Switching Protocols` означает, что аутентификация прошла. В противном случае:

| Статус | Тело | Решение |
| - | - | - |
| `401` | `{"code":-32401,"message":"missing API key"}` | Добавьте `?api_key=YOUR_LICENSE_KEY` в URL. Браузеры не могут задавать заголовки для WebSocket, поэтому параметр запроса — надёжный вариант |
| `403` | `{"code":-32402,"message":"invalid API key"}` | Ключ неверный или был перевыпущен. Скопируйте его заново из панели управления |
| `403` | `{"code":-32404,"message":"IP not whitelisted"}` | IP этой машины или этот регион не разрешены в вашей лицензии. Добавьте IP в панели управления или подключитесь к региону, который входит в лицензию |

Что ещё проверить:

* **Хост разрешается.** WebSocket работает на RPC-хостах: `wss://{region}.rpc.orbitflare.com`. Хостов `wss://mainnet.rpc...` и `wss://global.rpc...` не существует. Список приведён в разделе [Инфраструктура](/ru/infrastructure).
* **URL начинается с `wss://`.** Если передать клиенту WebSocket URL с `https://`, ошибка возникнет ещё до того, как запрос дойдёт до OrbitFlare.
* **Только для TypeScript:** `Cannot find package 'ws'` означает, что не установлена необязательная peer-зависимость. Выполните `npm install ws`.

## Соединение есть, но обновлений нет

Сервер подтверждает каждую подписку числовым идентификатором. Если вы его так и не получили, запрос был отклонён, и в ответе сказано почему:

```json theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Request: Invalid pubkey provided"},"id":1}
```

Во время отладки логируйте все сообщения от сервера, а не только уведомления. Ошибки приходят в тот же сокет, и их легко пропустить.

Если подписка принята, но молчит:

* **Аккаунт не меняется.** `accountSubscribe` срабатывает только при изменении данных или лампортов аккаунта. Проверьте на аккаунте, который заведомо активен, например `SysvarC1ock11111111111111111111111111111111`, который меняется каждый слот.
* **Фильтр ничему не соответствует.** Для `programSubscribe` и `logsSubscribe` адрес, который никогда не встречается в транзакциях, не порождает событий. Сначала проверьте адрес в обозревателе блоков.
* **Подпись старая.** `signatureSubscribe` знает только о недавних транзакциях. Для всего, что старше нескольких минут, вызывайте `getSignatureStatuses` с `searchTransactionHistory: true`. См. [Ожидание подтверждения транзакции](/ru/recipes#дождитесь-подтверждения-транзакции).

## Обрывы соединения

### Простаивающие соединения закрываются без предупреждения

Соединение без трафика в какой-то момент обрывается, причём резко, без фрейма закрытия, поэтому клиент видит код `1006` с пустой причиной. Поддерживайте соединение, отправляя **ping-фреймы** WebSocket каждые 20–30 секунд:

```javascript theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
const ws = new WebSocket(`wss://fra.rpc.orbitflare.com?api_key=${process.env.ORBITFLARE_LICENSE_KEY}`);

const keepalive = setInterval(() => ws.ping(), 25_000);
ws.on("close", () => clearInterval(keepalive));
```

> [!WARNING]
>
> JSON-RPC-сообщение вроде `{"method":"ping"}` не работает как keepalive. В Solana нет RPC-метода `ping`, поэтому сервер ответит `-32601 Method not found`. Используйте ping-фрейм уровня протокола, который предоставляет ваша библиотека.

SDK OrbitFlare отправляют ping-фрейм каждые 10 секунд и переподключаются после трёх пропущенных pong, поэтому при их использовании делать это самостоятельно не нужно.

### После переподключения подписки пропали

Подписки привязаны к соединению. Когда оно обрывается, они исчезают, и новое соединение начинается без подписок. Храните список того, на что вы подписывались, и после переподключения отправляйте эти запросы заново. Учтите, что идентификаторы подписок меняются.

SDK отслеживают подписки и переподписываются автоматически. Ваш цикл `sub.next()` продолжает работать после переподключений.

### Отписка не проходит

`Invalid subscription id.` означает, что такого идентификатора нет в этом соединении. Обычно соединение было заменено, и идентификатор принадлежит старому. Эту ошибку можно спокойно игнорировать.

### Слишком много соединений

С одного IP можно держать 50 одновременных WebSocket-соединений, этот лимит общий с gRPC. Откройте одно соединение и разместите в нём много подписок, а не открывайте отдельное соединение на каждую подписку. См. [лимиты соединений](/ru/authentication#лимиты-соединений-для-потоковой-передачи-данных).

## Если проблема не решена

Соберите регион, к которому подключаетесь, точный запрос подписки, все сообщения, которые прислал сервер, и код закрытия. Затем задайте вопрос в [Discord](https://discord.gg/orbitflare). С этими четырьмя данными большинство проблем удаётся определить с первого ответа.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.