Разбираем Server-Sent Events в ASP.NET Core и .NET 10. Окончание
Начало
Продолжение
Фильтрация SSE по пользователю
SSE построены на основе стандартного HTTP. Поскольку это стандартный GET-запрос, вся существующая инфраструктура «просто работает»:
- Безопасность - вы можете передать стандартный JWT в заголовке Authorization.
- Контекст пользователя - вы можете получить доступ к HttpContext.User, чтобы извлечь идентификатор пользователя и отфильтровать поток. Вы отправляете пользователю только те данные, которые ему принадлежат.
Вот пример конечной точки SSE, которая передаёт потоком только заказы для конкретного пользователя:
app.MapGet("orders/realtime", (
ChannelReader<OrderPlacement> reader,
// Внедрённый контекст с метаданными пользователя
IUserContext context,
CancellationToken ct) =>
{
// Реализация IUserContext получает UserId из токена доступа JWT
var userId = context.UserId;
async IAsyncEnumerable<OrderPlacement>
GetUserOrders()
{
await foreach (var order in
reader.ReadAllAsync(ct))
{
// Выдаём только данные текущего пользователя
if (order.CustomerId == userId)
yield return order;
}
}
return TypedResults.ServerSentEvents(
GetUserOrders(),
"orders");
})
// Стандартная авторизация ASP.NET
.RequireAuthorization();Обратите внимание, что при отправке сообщения в канал оно транслируется всем подключённым клиентам (ChannelReader<T>). Это вряд ли подойдёт, когда надо разделять сообщения для каждого пользователя. Поэтому в производственной среде понадобится более надёжная логика.
Обработка SSE в JavaScript
На стороне клиента не нужно устанавливать дополнительных npm-пакетов. Нативный API EventSource браузера берёт на себя основную работу, включая логику «повторного подключения и отправки Last-Event-ID», которую мы рассмотрели в предыдущем посте.
const es =
new EventSource('/orders/realtime/with-replays');
// Слушаем специальный тип событий 'orders', который определён в коде C# (см. выше)
es.addEventListener('orders', (event) => {
const payload = JSON.parse(event.data);
console.log(
`Новый заказ ${event.lastEventId}:`, payload.data);
});
// При открытии подключения
es.onopen = () => {
console.log('Connection opened');
};
// Обрабатываем общие сообщения (если есть)
es.onmessage = (event) => {
console.log('Получено сообщение:', event);
};
// Обрабатываем ошибки и переподключения
es.onerror = () => {
if (es.readyState === EventSource.CONNECTING) {
console.log('Повторное подключение…');
}
};
Итого
SSE в .NET 10 — это идеальный компромисс для простых односторонних обновлений, таких как панели мониторинга, уведомления и индикаторы выполнения. Они легковесны, работают по протоколу HTTP и легко обеспечивают безопасность с помощью существующего промежуточного ПО.
Однако SignalR остаётся надёжным и проверенным в боевых условиях вариантом для сложных двусторонних коммуникаций или масштабных задач, требующих бэкэнда.
Цель SSE не в замене SignalR, а в предоставлении более простого инструмента для более простых задач. Выбирайте самый простой инструмент, который решает вашу проблему.
Источник: https://www.milanjovanovic.tech/blog/server-sent-events-in-aspnetcore-and-dotnet-10