- Using server-sent events
- Receiving events from the server
- Sending events from the server
- Error handling
- Closing event streams
- Event stream format
- Fields
- Examples
- Data-only messages
- Named events
- Mixing and matching
- Server-Sent Events: пример использования
- Подготовка
- Сервер
- Клиент
- What is Server-Sent Events?
- Server-Sent Events: Why should you even learn anything about SSE?
- “I don’t care about your “Server-Sent stuff,” I have WebSockets!”
- “I don’t care about your “Server-Sent stuff,” I will request every half a second!”
- So what are Server-Sent Events?
- Event-stream (the cool name for Server-Sent Events messages)
- Client-Side
- Browsers
- Mobile apps
- Conclusion
Using server-sent events
Developing a web application that uses server-sent events is straightforward. You’ll need a bit of code on the server to stream events to the front-end, but the client side code works almost identically to websockets in part of handling incoming events. This is a one-way connection, so you can’t send events from a client to a server.
Receiving events from the server
The server-sent event API is contained in the EventSource interface; to open a connection to the server to begin receiving events from it, create a new EventSource object with the URL of a script that generates the events. For example:
If the event generator script is hosted on a different origin, a new EventSource object should be created with both the URL and an options dictionary. For example, assuming the client script is on example.com :
Once you’ve instantiated your event source, you can begin listening for messages from the server by attaching a handler for the message event:
This code listens for incoming messages (that is, notices from the server that do not have an event field on them) and appends the message text to a list in the document’s HTML.
You can also listen for events with addEventListener() :
This code is similar, except that it will be called automatically whenever the server sends a message with the event field set to «ping»; it then parses the JSON in the data field and outputs that information.
Warning: When not used over HTTP/2, SSE suffers from a limitation to the maximum number of open connections, which can be especially painful when opening multiple tabs, as the limit is per browser and is set to a very low number (6). The issue has been marked as «Won’t fix» in Chrome and Firefox. This limit is per browser + domain, which means that you can open 6 SSE connections across all of the tabs to www.example1.com and another 6 SSE connections to www.example2.com (per Stackoverflow). When using HTTP/2, the maximum number of simultaneous HTTP streams is negotiated between the server and the client (defaults to 100).
Sending events from the server
The server-side script that sends events needs to respond using the MIME type text/event-stream . Each notification is sent as a block of text terminated by a pair of newlines. For details on the format of the event stream, see Event stream format.
The PHP code for the example we’re using here follows:
The code above generates an event every second, with the event type «ping». Each event’s data is a JSON object containing the ISO 8601 timestamp corresponding to the time at which the event was generated. At random intervals, a simple message (with no event type) is sent. The loop will keep running independent of the connection status, so a check is included to break the loop if the connection has been closed (e.g. client closes the page).
Note: You can find a full example that uses the code shown in this article on GitHub — see Simple SSE demo using PHP.
Error handling
When problems occur (such as a network timeout or issues pertaining to access control), an error event is generated. You can take action on this programmatically by implementing the onerror callback on the EventSource object:
Closing event streams
By default, if the connection between the client and server closes, the connection is restarted. The connection is terminated with the .close() method.
Event stream format
The event stream is a simple stream of text data which must be encoded using UTF-8. Messages in the event stream are separated by a pair of newline characters. A colon as the first character of a line is in essence a comment, and is ignored.
Note: The comment line can be used to prevent connections from timing out; a server can send a comment periodically to keep the connection alive.
Each message consists of one or more lines of text listing the fields for that message. Each field is represented by the field name, followed by a colon, followed by the text data for that field’s value.
Fields
Each message received has some combination of the following fields, one per line:
A string identifying the type of event described. If this is specified, an event will be dispatched on the browser to the listener for the specified event name; the website source code should use addEventListener() to listen for named events. The onmessage handler is called if no event name is specified for a message.
The data field for the message. When the EventSource receives multiple consecutive lines that begin with data: , it concatenates them, inserting a newline character between each one. Trailing newlines are removed.
The event ID to set the EventSource object’s last event ID value.
The reconnection time. If the connection to the server is lost, the browser will wait for the specified time before attempting to reconnect. This must be an integer, specifying the reconnection time in milliseconds. If a non-integer value is specified, the field is ignored.
All other field names are ignored.
Note: If a line doesn’t contain a colon, the entire line is treated as the field name with an empty value string.
Examples
Data-only messages
In the following example, there are three messages sent. The first is just a comment, since it starts with a colon character. As mentioned previously, this can be useful as a keep-alive mechanism if messages might not be sent regularly.
The second message contains a data field with the value «some text». The third message contains a data field with the value «another message\nwith two lines». Note the newline special character in the value.
Named events
This example sends named events. Each has an event name specified by the event field, and a data field whose value is an appropriate JSON string with the data needed for the client to act on the event. The data field could, of course, have any string data; it doesn’t have to be JSON.
Mixing and matching
You don’t have to use just unnamed messages or typed events; you can mix them together in a single event stream.
Источник
Server-Sent Events: пример использования
Доброго времени суток, друзья!
В этом туториале мы рассмотрим Server Sent Events: встроенный класс EventSource, который позволяет поддерживать соединение с сервером и получать от него события.
О том, что такое SSE и для чего он используется можно почитать здесь.
Что конкретно мы будем делать?
Мы напишем простой сервер, который будет по запросу клиента отправлять ему данные 10 случайных пользователей, а клиент с помощью этих данных будет формировать карточки пользователей.
Сервер будет реализован на Node.js, клиент — на JavaScript. Для стилизации будет использоваться Bootstrap, в качестве API — Random User Generator.
Код проекта находится здесь.
Если вам это интересно, прошу следовать за мной.
Подготовка
Создаем директорию sse-tut :
Заходим в нее и инициализируем проект:
axios будет использоваться для получения данных пользователей.
Сервер
Приступаем к реализации сервера.
Подключаем http и axios, определяем порт:
Создаем функцию получения данных пользователя:
Создаем счетчик количества отправленных пользователей:
Пишем функцию отправки данных клиенту:
Создаем и запускаем сервер:
Выполняем команду yarn start или npm start . В терминале появляется сообщение «Server ready.». Открываем http://localhost:3000 :
С сервером закончили, переходим к клиентской части приложения.
Клиент
Открываем файл client.js .
Создаем функцию генерации шаблона пользовательской карточки:
Шаблон генерируется с использованием следующих данных: идентификатор пользователя (если имеется), имя, логин, адрес электронной почты и возраст пользователя.
Начинаем реализовывать основной функционал:
Сначала реализуем закрытие соединения:
Переходим к открытию потока событий:
Обрабатываем кастомное событие «randomUser»:
Не забываем реализовать обработку ошибок:
Наконец, инициализируем приложение:
На всякий случай перезапускаем сервер. Открываем http://localhost:3000 . Нажимаем на кнопку «Start»:
Начинаем получать данные от сервера и рендерить карточки пользователей.
Если нажать на кнопку «Stop», отправка данных будет приостановлена:
Снова нажимаем «Start», отправка данных продолжается.
При достижении лимита (10 пользователей) сервер отправляет идентификатор со значением -1 и закрывает соединение. Клиент, в свою очередь, также закрывает поток событий:
Как видите, SSE очень похож на веб-сокеты. Недостатком является однонаправленность сообщений: сообщения могут отправляться только сервером. Преимущество состоит в автоматическом переподключении и простоте реализации.
Поддержка данной технологии на сегодняшний день составляет 95%:
Надеюсь, статья вам понравилась. Благодарю за внимание.
Источник
What is Server-Sent Events?
After discussing with plenty of developers during the last few months, I have realized that a huge portion of them don’t know what “Server-Sent Events” (or “SSE” or “EventSource”) is. My aim here is to give you all the information you may need about Server-Sent Events.
Server-Sent Events: Why should you even learn anything about SSE?
As the economy and your users are more and more real-time oriented, you need Server-Sent Events if displaying the last data updates to your users may change their actions. The data itself need not change often, but when it changes, you really want users to know it!
Let’s look at some cases before we explain the technical details:
– Users may click on the last news available rather than shutting down the page.
– Services/product availability. If you sell products or services rare for this specific client (car-sharing, docks for bike-sharing, promotions with limited stocks…), you want to make sure your prospect knows it is available as soon as possible.
– Prices
– Social/chat… no need to explain!
– You may just want to display rapidly changing data: game score, trading, dashboard…
“I don’t care about your “Server-Sent stuff,” I have WebSockets!”
Ok, WebSockets are trendy, fast, and easy to implement now, but:
1) It means you already understood that you need something better than HTTP Polling. Good!
2) There are pros/cons for WebSocket and SSE. I suggest you read this blog post and come back here afterward… I will be waiting for you…
If you are lazy, here is a very short summary. WebSockets are bilateral (you don’t always need bi-direction), not HTTP (some proxy won’t let it go through) “protocol” without standards for error handling. SSE is mono-directional (server to client), HTTP protocol with error handling standards. Both improve hugely latency for users. From a server load point of view, we achieved better performance with SSE than WebSockets (a higher number of final users handled by one server). Read more about AMPLIFY Streams.
“I don’t care about your “Server-Sent stuff,” I will request every half a second!”
… Now we need to explain a little more what Server-Sent Events are.
So what are Server-Sent Events?
A client subscribes to a “stream” from a server and the server will send messages (“event-stream”) to the client until the server or the client closes the stream. It is up to the server to decide when and what to send the client, for instance, as soon as data changes.
To fully understand SSE, we need to explain polling. The “historical” method of receiving information is to ask for it. The good old “request/response” paradigm! When you poll, the client-side asks for information and a server gives back the information available. No way to get something without asking it. With AJAX, you can make the polling happen with a pre-defined frequency.
(To optimize server load and bandwidth, you could decide that the server answers “No content” if the content has not changed since the last client request… but it means your API is not RESTful anymore.
Comparing polling, long-polling & SSE messages for real-time updates
Well, there are five major consequences of this ongoing polling:
– You will overcharge the server load. It is hard to make benchmarks comparing SSE and “machine-gun” polling because it is depending on the frequency of polling data itself, the server configuration, etc. When we compared different scenarios, we ended up with a factor of three to 10: one SSE server can handle three to 10 times more users than a polling server (with the same objectives of latency).
– You will overload networks with useless data because the polling will send data even if they didn’t change! This is bad for the server-side and client-side costs and terrible for the planet (this one is maybe why I am writing this blog post! Did you know the web environmental footprint is equivalent to 40 nuclear plants in energy consumption and the whole civil flight in greenhouse gas?).
Again, benchmarking polling versus streaming depends on the dataset, but we have tested it on various public APIs, and the gain varies from 20% (all data is changing often, we are just saving headers & round-trips) to 95% (small parts of the dataset is not changing not that often).
– Pushing consumes 75% to 95% less end-user battery than polling (here is the study)… don’t you want your user to keep on using your app?
– Polling requiring 3 round-trips (TCP SIN, SSL, and Data). In 3G, one round-trip takes 150 ms. So one polling will need 450 ms before the mobile receive any useful data. Once the connection is set with SSE, the mobile will receive new data in 75ms (as it directly sends data from the server to the client).
– Last but not least: you won’t be proud of your code!
TLDR: polling to display real-time data feels like this:
With Long-Polling (Hanging GET / COMET), the server will wait for a change of data before sending the response. The server will “hold” the request until it makes sense to send something. It might look attractive because you will alleviate useless responses, but it requires hacks (such as appending script tags to an “infinite” iframe) and server loads which are still huge. How do you handle “up-dates” queuing, missed messages, and disconnections?
So why won’t you use a W3C standard built for real-time downstream?
We will first have a look at the messages themselves, then client-side implementation, and finally server-side one.
Event-stream (the cool name for Server-Sent Events messages)
The event-stream is a simple stream of text data which must be encoded using UTF-8. Messages in the event-stream are separated by a pair of newline characters (“\n”).
The following field names are defined in the specification:
Event: The event’s type. It will allow you to use the same stream for different content. A client can decide to “listen” only to one type of event or to interpret differently each event type.
Data: The data field for the message. You can put consecutive “data” lines.
ID: ID for each event-stream. Useful to track lost messages.
Retry: The time to use before the browser attempts a new connection after all connections are lost (in milliseconds). The reconnection process is automatic and is set by default at three seconds. During this reconnection process, the last ID received will be automatically sent to the server… something you would need to code by yourself with WebSockets or Long-polling.
“:” : if you start the message by a colon, it will be considered as comments
And yes, you can easily send JSON format without breaking the synthax! And that is a very very good news!
Client-Side
Browsers
Since Server-Sent Events is a W3C standard defining a Web-based API, the client-side for the web is simple and direct.
Here is an example taken from this link. It handles the connection to the server, listening to messages, and handling of those messages.
One problem is that all browsers do not support EventSource
Source: http://caniuse.com/#search=Server-sent
So you will have to test if your user browser supports SSE
If the browser does not support SSE, you can use a Polyfill. We have tested several ones available in GitHub and have decided to use this one for our own SDKs:
For more code samples, you can check our own SDK or demos (quizz with D3.js, display of financial data)
Mobile apps
For mobile apps, there is no standard API. Things are a little more complicated, so my best option is to give links to libraries and some other blog posts detailing code samples.
Android
iOS
Conclusion
We advocate the use of high standards, and we believe each individual (it includes developers) should think twice before consuming unneeded resources. When an app/website needs some data updated in real-time, and there is not a need for upward data flow, Server-Sent Events should be considered first. If you disagree, please comment on this article below and we will happily reply.
Источник