SSE (Server-sent Events) is a lightweight alternative to WebSocket, using the HTTP protocol.
Strictly speaking, the HTTP protocol is not a way to do server push, but when the server to the client state to send flow information, the client will keep the connection open, SSE uses this principle.
What can SSE do?
In theory, SSE and WebSocket do the same thing. When you need to update a network application with new data locally, SSE can do it without requiring the user to perform any action.
For example, we want to do a statistical system management background, we want to know the statistics of the real-time situation. Similar to this frequent, low-latency scenario, SSE can be fully satisfied.
Some other applications: for example, new email alerts for email services, new message push for Weibo, real-time synchronization of some operations in the background, etc., SSE is a good choice.
SSE vs. WebSocket
SSE is a one-way channel, only the server sends messages to the client, and if the client needs to send a message to the server, a new HTTP request is required. This compares to the WebSocket duplex channel, there is a greater overhead. There will be a "when do we need to care about this difference?" Problem, if the average message is sent to the server once per second, then WebSocket should be chosen. If only 5-6 times a minute, the difference is not very big.
In terms of browser compatibility, the two are similar. Earlier, Flash was used whenever a two-way Socket was needed, and WebSocket compatibility was difficult to do in the case of a mobile browser that did not support Flash.
SSE I think the biggest advantage is the convenience:
- Implementing a complete service requires only a small amount of code;
- Can be used in existing services, do not need to start a new service;
- Can be used in any kind of service-side language;
- Based on the HTTP/HTTPS protocol, it can run directly on the existing proxy server and authentication technology.
With these advantages, you have saved a lot of cost for your project when you choose to use SSE.
Simple Example
The following is a simple example of implementing a SSE service.
Server
'Use Strict';ConstHTTP = require ('http'); Http.createserver ((req, res)= { //the server declaration next sends an event streamRes.writehead ( $, { 'Content-type':'Text/event-stream', 'Cache-control':'No-cache', 'Connection':'keep-alive', 'Access-control-allow-origin':'*', }); //Send MessageSetInterval (() ={res.write ('event:slide\n');//Event TypeRes.write (' ID: ${+NewDate ()}\n ');//message IDRes.write ('data:7\n');//message DataRes.write ('retry:10000\n');//re-connect timeRes.write ('\ n');//End of Message}, the); //Send comment Keep long connectionSetInterval (() ={res.write (': \ n'); }, 12000);}). Listen ( -);
The server first declares to the client that the next event stream (Text/event-stream) type of data is sent, and then it can send the message to the client multiple times.
The event stream is a simple text stream that only supports encoding in the UTF-8 format. Each message is delimited with a blank line.
4 fields were defined for the message in the specification:
The event type of an event message. When the client receives the message, an event is triggered on the current EventSource object, and the name of the event is the value of the field, and if the message does not have this field, the client's EventSource object triggers the default message event.
ID of this message. After the client receives the message, it takes the ID as an internal attribute and sends it to the Last-Event-ID
server after the disconnection is successful Last-Event-ID
.
The data field of the information message. The client parses the field into a string, and if a message has more than one data field, the client automatically connects to a string with a newline character.
Retry Specifies the time that the client is re-connected. Only integers are accepted, in milliseconds. If the value is not an integer, it is automatically ignored.
One interesting thing is that the specification specifies that messages beginning with a colon are treated as comments, and a common comment ( :\n\n
) is 5 characters for the server, but no events are triggered when sent to the client, which is very friendly to the client. So annotations are generally used to maintain long connections between the server and the client .
Effect:
Client
We created an EventSource
object that passed in the parameter: url
. and responds based on the status of the server and the information sent.
'Use Strict';if(window. EventSource) {//Creating a EventSource object Connection server ConstSource =NewEventSource ('http://localhost:2000'); //The Open event is triggered when the connection is successfulSource.addeventlistener ('Open', () ={Console.log ('Connected'); }, false); //when the server sends information to the client, the message event is triggered by default if there is no event fieldSource.addeventlistener ('message', E ={console.log (' data: ${e.data} '); }, false); //custom EventHandler, which is triggered when a message is received from the event field slideSource.addeventlistener ('Slide', E ={console.log (' data: ${e.data} ');//= Data:7},false); //An Error event is triggered when a connection exception occurs and automatically re-connectsSource.addeventlistener ('Error', E = { if(E.target.readystate = = =eventsource.closed) {Console.log ('Disconnected'); } Else if(E.target.readystate = = =eventsource.connecting) {Console.log ('Connecting ...'); } }, false);} Else{console.error ('Your Browser doesn\ ' t support SSE');}
EventSource inherits properties and methods from the parent interface Eventtarget, with 3 EventHandler Properties,2 read-only properties, and 1 methods built into it:
EventHandler Property
Eventsource.onopen is called when the connection is open.
Eventsource.onmessage is called when a message with no event property is received.
Eventsource.onerror is called when an exception is connected.
read-only properties
eventsource.readystate A unsigned short value that represents the connection status. The possible values are connecting (0), OPEN (1), or CLOSED (2).
The URL of the eventsource.url connection.
Method
eventsource.close () Close the connection
Effect:
how SSE guarantees data integrity
Each time the client receives a message, it stores the ID field of the message as an internal attribute Last-Event-ID
.
SSE supports the disconnection mechanism by default, which triggers the EventSource error event when the connection is disconnected and automatically re-connects. Once the connection succeeds, EventSource will Last-Event-ID
send the attribute as the request hair to the server, so that Last-Event-ID
the server can make the corresponding processing according to this.
It is important to note that the ID field is not required, and the server may not have an ID field in the message, so the client does not have Last-Event-ID
this property. So to keep the data reliable, we need to take the ID field on each message.
Reduce overhead
In SSE's draft, it was mentioned that the "Text/event-stream" MIME type transmission should be automatically disconnected after 15 seconds of static. This mechanism can also be found in actual projects, but the time of disconnection is not included in the standard.
To reduce the overhead of the server, we can also disconnect and re-connect for purposes.
The easy way is for the server to send a shutdown message and specify a reconnection timestamp, the client closes the current connection when the Shutdown event is triggered, and creates a timer that destroys the timer when it is re-connected.
'Use Strict'; function Connectsse () {if(window. EventSource) {ConstSource =NewEventSource ('http://localhost:2000'); Let Reconnecttimeout; Source.addeventlistener ('Open', () ={Console.log ('Connected'); Cleartimeout (reconnecttimeout); }, false); Source.addeventlistener ('Pause', E ={source.close (); ConstReconnecttime = +E.data; ConstCurrentTime = +NewDate (); Reconnecttimeout= SetTimeout (() ={Connectsse (); }, Reconnecttime-currenttime); }, false); } Else{console.error ('Your Browser doesn\ ' t support SSE'); }}connectsse ();
Browser compatible
Backwards compatibility: The most common way to achieve real-time data updates earlier is polling.
Polling is to manage the update of data by sending a request to the server at a fixed frequency and returning new data when the server has data updates. This kind of polling method is not only expensive, but also the efficiency and frequency of the update, it can not achieve the purpose of timely updating.
Then a long polling occurs: After the client sends a request to the server, the server suspends the request temporarily, waits until the data is updated and returns the latest data to the client, and the client sends a request to the server after receiving the new message. Unlike regular polling, data can be updated in real time to reduce unnecessary overhead.
Is there a "choose long polling or regular polling?" "The proposition that long polling is not always better than regular polling occupies an advantage?" We can analyze from the perspective of bandwidth consumption, if a program data update is too frequent, assuming 2 updates per second, if the use of long polling every minute to send 120 HTTP requests. If you use regular polling to send a request every 5 seconds, only 20 times a minute, from here, regular polling is more dominant.
The key difference between long polling and SSE is that each time a data update requires an HTTP request. Like WebSocket and SSE, long polling also takes up a socket. In the data update efficiency and SSE almost, a data update can be detected. Plus all browsers are supported, is a good SSE alternative.
This paper introduces the usage of SSE and some techniques in the process of using it. Compared with Websocket,sse, the development time and cost have a great advantage. To do data push service, in addition to Websocket,sse is also a good choice, I hope to be helpful to everyone.
SSE: Using HTTP for data push applications