Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use server-sent-events in express.js

I setup my REST server with express.js. Now I want to add sse to this server. After I implemented this sse package, I get an error. I know that I get this error, when would try to use res.send twice, but I am not.

ERROR: Error: Can't set headers after they are sent.                                            
    at ServerResponse.OutgoingMessage.setHeader (http.js:690:11)                            
    at ServerResponse.header (/home/root/node_modules/express/lib/response.js:718:10)         
    at ServerResponse.send (/home/root/node_modules/express/lib/response.js:163:12)            
    at app.get.str (/home/root/.node_app_slot/main.js:1330:25)                                 
    at Layer.handle [as handle_request] (/home/root/node_modules/express/lib/router/layer.js:95:5)    
    at next (/home/root/node_modules/express/lib/router/route.js:131:13)                       
    at sse (/home/root/node_modules/server-sent-events/index.js:35:2)                          
    at Layer.handle [as handle_request] (/home/root/node_modules/express/lib/router/layer.js:95:5)  
    at next (/home/root/node_modules/express/lib/router/route.js:131:13)                          
    at Route.dispatch (/home/root/node_modules/express/lib/router/route.js:112:3)

Is it possible that I can't use the express methods anymore within the sse function? For example:

app.get('/events', sse, function(req, res) {
    res.send('...');
});

Furthermore, I found this solution and this. Is it possible to make sse with the res.write function or in another way without using another package?

like image 955
Steckdoserich Avatar asked Jan 07 '16 14:01

Steckdoserich


People also ask

What is Server Sent Events (SSE)?

LinkedIn uses server sent events for their messaging service, Mapbox uses SSE to display live map data, and many analytics tools use SSE to show real-time user reports. SSE will only become more prominent as monitoring tools and real-time events become more relevant to users.

How to use Server-Sent Events?

Using server-sent events 1 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 ... 2 Sending events from the server. ... 3 Error handling. ... 4 Closing event streams. ... 5 Event stream format. ...

How do I send events from the server side?

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.

How to write SSE events in express?

The Express side is the tricky part. To support SSE, you need to set 3 headers, and then send the headers to the client using flushHeaders (): Content-Type: text/event-stream: So the client knows this response is an HTTP stream Once you've called flushHeaders (), you can then start writing events using the res.write () function.


Video Answer


1 Answers

I disagree with using Socket.IO to implement basic Server-Sent Events. The browser API is dead simple and the implementation in Express requires only a couple of changes from a normal response route:

app.get('/streaming', (req, res) => {

    res.setHeader('Cache-Control', 'no-cache');
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Connection', 'keep-alive');
    res.flushHeaders(); // flush the headers to establish SSE with client

    let counter = 0;
    let interValID = setInterval(() => {
        counter++;
        if (counter >= 10) {
            clearInterval(interValID);
            res.end(); // terminates SSE session
            return;
        }
        res.write(`data: ${JSON.stringify({num: counter})}\n\n`); // res.write() instead of res.send()
    }, 1000);

    // If client closes connection, stop sending events
    res.on('close', () => {
        console.log('client dropped me');
        clearInterval(interValID);
        res.end();
    });
});
  • Set the appropriate headers as per the spec
  • Use res.flushHeaders() to establish SSE connection
  • Use res.write() instead of res.send() to send data
  • To end stream from the server, use res.end()

The snippet above uses setInterval() to simulate sending data to the client for 10 seconds, then it ends the connection. The client will receive an error for the lost connection and automatically try to re-establish the connection. To avoid this, you can close the client on error, or have the browser send a specific event message that the client understands means to close gracefully. If the client closes the connection, we can catch the 'close' event to gracefully end the connection on the server and stop sending events.

express: 4.17.1 node: 10.16.3

like image 60
John Galt Avatar answered Oct 28 '22 23:10

John Galt