Server sent events (SSE) & EventSource client use and server basic implementation (based on Node.js)

Keywords: Javascript node.js server

objective

The traditional Web front and back communication is mainly carried out by HTTP. Usually, the foreground actively requests to the background for what it needs, and the background cannot directly send data to the front. Usually, if the background data changes frequently, the foreground mainly depends on polling or long connection. Both methods are not very elegant.

Now, there are two schemes to deal with this problem: WebSocket and server sent events (SSE). WebSocket can realize real-time two-way communication, which is very powerful in function, but it is a new technology compared with HTTP. Server sent events is a function extended over HTTP, a bit like the long connection mentioned above, but it is a native standard, more perfect in function and more convenient to use. This article will explain the contents related to server sent events.

Basic description

Server sent events is a function added to H5. It is an extended function on HTTP, so that the server can actively send data to the client. Use the EventSource interface on the client side to process server send events.

The core of server sent events is to add a MIME type: text / event stream. Look at the name to know that this is a stream. As long as it doesn't end, it can always transfer data.

In actual use, as long as the client actively initiates the access interface, it doesn't matter after the connection is established, and the server will actively push messages when needed.

One advantage of the native function of server sent events is that the browser will automatically reconnect by default.

Basic use

Client use

The client uses the EventSource interface to process server sent events. The main methods of use are as follows:

    var es = new EventSource("/sse"); // Declare the EventSource object and connect the url

    es.onmessage = (e) => {} // Triggered when a server message is received

    es.onopen = (e) => {} // Triggered when the connection is established

    es.onerror = (e) => {} // Triggered when an error occurs

    // es.close(); //  Close EventSource connection

    // console.log(es.url); 

    // console.log(es.readyState); //  Connection status: 0 - connecting; 1 - open; 2 - closed; 

The basic use of the client is relatively simple. The demonstration needs to be combined with the following server.

For the front end, SSE can be used by directly using the EventSource interface of JS. For other languages as clients, there may be no ready-made methods available, but it is also very simple to use. Use the GET method to access the link and include the following attributes in the header file (only recommended, not required):
accept: text/event-stream
cache-control: no-store
connection: keep-alive
Then you can establish the connection, and then wait and process the data from the server.

Server implementation

Server sent events is a function extended from HTTP, so the server implementation only needs a little processing on the basis of HTTP server. The most important thing is to set the MIME type in the response header to text / event stream. The following is the simplest example:

const http = require('http')

const server = http.createServer((req, res) => {

     // Visit link / sse
    if (req.url == '/sse') {
        res.writeHead(200, {
            "Content-Type": "text/event-stream",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
        });
        res.write("data: " + 'connected' + "\n\n");

        // The server sends messages to the client regularly
        interval = setInterval(function () { 
            res.write("data: " + 'hello world' + "\n\n");
        }, 5000);

        // Req. On ('close ', () = > {}) / / triggered when the client disconnects

        return
    }

    // Any other links return to the web page
    res.statusCode = 200
    res.end(`
    <script>
        var es = new EventSource("/sse");
        es.onmessage = (e) => { console.log(e); }
        es.onopen = (e) => { console.log(e); }
        es.onerror = (e) => { console.log(e); }
    </script>
    `)
})

server.listen(80, '127.0.0.1', () => {
    console.log(`Server running at http://127.0.0.1/`)
})


In the above example, the server returns the 200 status code after receiving the connection request from EventSource, and adds text / event stream to the response header. After these contents are sent to the client, the connection is completed. Then, as long as the server sends a message to the client when necessary, the timer is used in the above example to simulate sending a message.

The data sent by the server in server send events must be UTF-8 encoded text with certain format requirements:

  • The data must be sent section by section, and there must be a blank line between each end
    For example, \ n\n in the above example, the latter newline character provides a blank line
  • There is a specific identification field before the data
    For example, in the above example, sending a message uses data: data text

The optional values of the identification field mentioned above are as follows:

  • data:
  • event:
    Define the event type. If this item is not set, sending data will trigger the message event, that is, the default onmessage method;
  • id:
    The number used to identify the current piece of information. The client can obtain it through the lastEventId attribute. If the connection is disconnected, the client will fill in the latest id in the last event id field in the request header when establishing reconnection;
  • retry:
    Specify the time interval for the browser to re initiate the connection;
  • :
    For the information that will be ignored, the server in the network may close the connection that has not transmitted data for a long time (such as 15 seconds). You can use this method to send messages to maintain the connection;

Some of the above contents can be tested in the following ways:

const http = require('http')

const server = http.createServer((req, res) => {

     // Visit link / sse
    if (req.url == '/sse') {
    	console.log(req.headers);
        res.writeHead(200, {
            "Content-Type": "text/event-stream",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
        });
        res.write("retry: 10000\n");
        res.write("event: connected\n");
        res.write("data: connected\n\n");


        // The server sends messages to the client regularly
        interval = setInterval(function () { 
            res.write("data: " + "hello world" + "\n");
            res.write("id: " + "aaa" + "\n\n");

            res.write("event: " + "naisu" + "\n");
            res.write("data: " + "233~~~" + "\n\n");
        }, 5000);

        return
    }

    // Any other links return to the web page
    res.statusCode = 200
    res.end(`
    <script>
        var es = new EventSource("/sse");
        es.onmessage = (e) => { console.log(e); } // Fetch data using data
        es.addEventListener("connected", (e) => { console.log(e) }, false); // Listen for custom events
        es.addEventListener("naisu", (e) => { console.log(e) }, false); // Listen for custom events
    </script>
    `)
})

server.listen(80, '127.0.0.1', () => {
    console.log(`Server running at http://127.0.0.1/`)
})

matters needing attention

Although server sent events is simple, there are still some matters to pay attention to when using it:

  • Browser connection limit
    Most browsers have a limit on the number of connections to the same IP or domain name (for example, the upper limit of chrome is 6). For ordinary HTTP requests, it's no problem to connect and disconnect again, but server send events is a long connection, and you can't connect more than 6;
  • The data connection that has not been transmitted for a long time is closed
    In the real environment, data transmission may pass through network nodes such as proxy server, which may close the connection that has not transmitted data for a long time;
  • Data is not transmitted in real time
    In the real environment, data transmission may pass through proxy servers and other network nodes. These nodes may cache data and forward it after reaching a certain amount. Relevant caches can be closed to improve real-time performance;

summary

Generally speaking, the use of server sent events is quite simple. For more information, please refer to the following link:
https://html.spec.whatwg.org/multipage/server-sent-events.html
http://www.ruanyifeng.com/blog/2017/05/server-sent_events.html

Posted by phpbeginner0120 on Mon, 25 Oct 2021 20:04:23 -0700