Сервера push sse понять?

Node.js внешний интерфейс сервер WebSocket

привет~ Уважаемые наблюдатели и господа, Привет всем~ Первая неделя китайского Нового года закончилась, и пришло время начать составлять новый план работы. Основным ответственным проектом является платформа визуализации данных, и если у сервера есть возможность отправить страницу для получения соответствующих уведомлений, можно добиться многих функциональных оптимизаций. Ввиду того, что Node-сторона проекта официально введена в эксплуатацию, а у front-end есть свой сервер, заниматься делами, естественно, гораздо удобнее.

Выбор технологии: SSE (отправленные сервером события) или WebSocket

Несколько лет назад у сервера не было возможности активно пушить, в основном за счет опроса, чтобы добиться возможности аппроксимации пуша сервера. Сейчас нет нужды так утруждать себя, опрос — это только решение с обратной совместимостью, а нынешняя мейнстримная прошивка сервера реализована с использованием SSE или WebSocket. Сравнение между ними выглядит следующим образом:

Основано ли оно на новом соглашении? Двусторонняя ли связь Поддерживать ли междоменное стоимость доступа
SSE нет(Http) Нет (сервер однонаправленный) Нет (Firefox поддерживает междоменный доступ) Низкий
WebSocket Да(ws) да да высоко

Одна вещь, которая нуждается в небольшом объяснении, — это стоимость доступа. SSE — это относительно легкий протокол, (Node) код относительно прост в реализации, а WebSocket — более сложный протокол. реализация на стороне сервера не сложная. При этом для реализации WebSocket нужно запустить еще один сервис, а SSE это не нужно.

После сравнения у меня есть общее представление о SSE и WebSocket. Требованием проекта к серверу push является отправка уведомлений, и в будущем может потребоваться доступ к функции синхронизации в реальном времени.После объединения фактической ситуации проекта и стоимости доступа был выбран SSE.

Наконец, взгляните на поддержку браузера для справки:

IEСразуlet it goНу, в повседневной жизни он не поддерживается ~ Другие браузеры все еще зеленые, и поддержка все еще довольно высока.

Пример

Сторона узла

В качестве каркаса в проекте используется яйцо, а нижний слой — Koa2, поэтому Koa2 используется в качестве примера. Код ключа на стороне узла выглядит следующим образом:

app.use(async (ctx) => {
  const { res, request: { url } } = ctx;
  res.writeHead(200, {
    'Content-Type': 'text/event-stream', // 服务器声明接下来发送的是事件流
  });
  let stream = new PassThrough();
  let i = 0;
  let timer = setInterval(() => {
    if (i === 5) {
      stream.write('event: pause\n'); // 事件类型
    } else {
      stream.write('event: test\n'); // 事件类型
    }
    stream.write(`id: ${+new Date()}\n`); // 消息ID
    stream.write(`data: ${i}\n`); // 消息数据
    stream.write('retry: 10000\n'); // 重连时间
    stream.write('\n\n'); // 消息结束
    i++;
  }, 1000);

  stream.on('close', function() {
    console.log('closed.')
    clearInterval(timer);
  })

  ctx.body = stream;
});

Сервер сообщает клиенту, что возвращаемый тип является потоком событий (текст/поток событий), см.MDNВ документации показано, что поток событий — это просто поток текстовых данных, и текст должен быть закодирован в формате UTF-8. Каждое сообщение отделяется пустой строкой. Строки комментариев к поведению, начинающиеся с двоеточия, игнорируются.

Затем следует тело сообщения, хотя в примере используетсяsetIntervalСимуляция постоянно отправляет push-уведомления, но также можно переключиться на запуск push-уведомлений с произвольными условиями.stream.writeВызывается 5 раз, соответствуя каждому полю в спецификации, понимается следующим образом:

  • eventявляется типом события сообщения. клиент вEventSourceсквозьaddEventListenerСлушайте соответствующие новости. Это поле можно опустить, и клиент инициируетmessageмероприятие.
  • idэто идентификатор события. Как значение свойства "идентификатора последнего события" внутри клиента, оно используется для повторного подключения и не может быть опущено.
  • dataКороче говоря, это поле данных сообщения после того, как клиент прослушает некоторое время, черезe.dataполученные данные.
  • retryДля времени переподключения этот параметр можно не указывать.
  • Наконец, уведомление заканчивается\n\n, нельзя опускать. За исключением имен полей, указанных выше, все остальные имена полей игнорируются.

Более подробное объяснение можно найти вMDNдокументация. Следует отметить небольшую деталь: в черновике SSE упоминается, что передачи MIME-типа «текст/поток событий» должны автоматически отключаться через 15 секунд бездействия. Однако после фактического измерения (только с помощью Chrome) было обнаружено, что даже если статическое время превышает 15 секунд, браузер и клиент не будут отключены. Прочитав множество статей, рекомендуется вести набор рассылки\n\nмеханизм сердцебиения. Лично я думаю, что это поможет улучшить надежность клиентской программы, но это не обязательно.

Наконец, прослушайте поток событийcloseСобытие, используемое для завершения этой ссылки. После тестирования выяснилось, что стоит ли давать клиенту звонитьcloseметод (примеры ниже) или аварийное завершение, в том числе закрытие окна, закрытие программы и т. д., могут вызватьcloseмероприятие.

клиент

Код клиента проще, пример такой:

const source = new EventSource('http://localhost:3000/test');

source.addEventListener('open', () => {
  console.log('Connected');
}, false);

source.addEventListener('message', e => {
  console.log(e.data);
}, false);

source.addEventListener('pause', e => {
  source.close();
}, false);

Обувь передней стороны Для такого кода должна быть довольно знакомой, все происходит с учетом событий, соответствующий код выполнен в соответствии с различными событиями. Объяснить немногоEventSourceЯ считаю, что со свойствами и методами каждый может с удовольствием использовать его.

EventSourceЕсть три события по умолчанию, а именно:

  • open: Вызывается при открытии соединения.
  • message: Вызывается при получении сообщения без атрибута события.
  • error: вызывается при возникновении ошибки.

Два свойства только для чтения:

  • readyState: представляет состояние подключения. Возможные значения: ПОДКЛЮЧЕНИЕ (0), ОТКРЫТО (1) или ЗАКРЫТО (2).
  • url: представляет URL-адрес соединения.

Метод:

  • close: Закрыть соединение после звонка (то есть упомянутого выше).

Более подробное объяснение можно найти вMDNДокументация

резюме

Это конец краткого введения в SSE сервера.Как видите, SSE относительно прост в разработке, а стоимость доступа очень низкая. Но это не значит, что WebSocket — это плохо, говорить о бизнесе в отрыве от реального сценария — это хулиганство. Кроме того, приведенный выше код является лишь демонстрацией и может быть дополнительно оптимизирован. Например, чтобы уменьшить нагрузку на сервер, можно установить механизм для целенаправленного отключения и повторного подключения, и вы можете реализовать его самостоятельно.

Соответствующий код был удаленGithub, добро пожаловать на чтение.

Спасибо всем судьям за то, что увидели это, легче сказать, чем сделать, надеюсь, эта статья будет вам полезна~ Спасибо!

использованная литература

20 строк кода для написания службы отправки данных

использовать сервер для отправки событий

EventSource