Перейти к основному содержимому

Практикум — WebSocket и события заказов

Разработчику

Практикум, шаг 7 из 8. Живые уведомления на orders-api. Теория — WebSockets в 8.05.


Зачем WebSocket здесь

После POST /api/v1/orders клиенту нужно узнать о смене статуса (reservedconfirmed) без polling. orders-api держит канал ws://localhost:5200/ws/orders и рассылает события подписчикам того же пользователя.


Формат сообщений (прикладной протокол)

Все кадры — текстовый JSON (UTF-8). Версия протокола в каждом сообщении:

{
"v": 1,
"type": "order.status_changed",
"payload": {
"orderId": "ord_x9y8",
"status": "confirmed",
"at": "2026-05-27T10:20:00Z"
}
}
typeНаправлениеСмысл
pingклиент → серверkeep-alive
pongсервер → клиентответ на ping
order.status_changedсервер → клиентсмена статуса заказа
errorсервер → клиент{ "code": "unauthorized", "message": "..." }

Hub в ASP.NET Core

Services/OrderWebSocketHub.cs:

Код ITЗагрузка примера кода…

OrderEventPublisher вызывает BroadcastToUserAsync после Confirm / Cancel.


Middleware маршрута

Program.cs:

Код ITЗагрузка примера кода…

JWT на handshake — через ?access_token= (см. шаг 6) или заголовок Authorization там, где прокси его не срезает.


Проверка в браузерной консоли

const token = "…"; // из POST /api/v1/auth/token
const ws = new WebSocket(`ws://localhost:5200/ws/orders?access_token=${token}`);
ws.onmessage = (e) => console.log(JSON.parse(e.data));
ws.onopen = () => ws.send(JSON.stringify({ v: 1, type: "ping" }));

Создайте заказ во второй вкладке Postman — в консоли придёт order.status_changed.


Масштабирование

In-memory ConcurrentBag работает на одном экземпляре. При горизонтальном масштабировании:

  • Redis pub/sub или SignalR backplane для fan-out;
  • sticky sessions на балансировщике как временная мера;
  • события как Kafka/RabbitMQ — если нужна история и гарантия доставки.

Для практикума достаточно одного процесса dotnet run.


Переподключение клиента

Браузер и Postman периодически рвут WS. Рекомендуемый алгоритм на клиенте:

  1. При onclose — экспоненциальная задержка (1 с, 2 с, 4 с … до 30 с).
  2. После onopenGET /api/v1/orders/{lastKnownId} для сверки статуса.
  3. Не полагаться только на пропущенные WS-сообщения при долгом офлайне.

Коды закрытия (RFC 6455):

КодСмысл в OrderDesk
1000Нормальное закрытие сессии
1008Policy violation (просрочен JWT)
1011Внутренняя ошибка сервера

Сверка с песочницей

Кнопка WS ping на intro отправляет { "type": "ping" } и показывает pong. После POST confirm в ручном режиме в ленте появится order.status_changed — тот же JSON, что ожидается в Postman WebSocket.


Следующий шаг

Соберём полный сценарий в Postman: шаг 8.