Home >Web Front-end >JS Tutorial >How to Use Server-sent Events in Node.js

How to Use Server-sent Events in Node.js

Joseph Gordon-Levitt
Joseph Gordon-LevittOriginal
2025-02-08 09:31:09231browse

How to Use Server-sent Events in Node.js

Core points

  • Server Send Events (SSE) enables the server to push data to the browser at any time, enabling functions such as real-time news reports, weather forecasts, and stock prices. The browser issues an initial request to establish a connection, and the server keeps the connection open to send a text message.
  • SSE is simpler than WebSockets, uses standard HTTP, supports one-way communication, and provides automatic reconnection. The server can terminate the SSE response at any time, but if the connection is interrupted, the browser will automatically attempt to reconnect.
  • The server can provide any number of SSE channel URLs or a single endpoint URL. Messages from the server may have associated events to identify a particular type of information. The server can also send an ID after the data line to resend any missed messages when the connection is disconnected.
  • The browser can terminate SSE communication using the .close() method of the EventSource object. The server can terminate the connection by triggering res.end() or sending a retry delay, and then return an HTTP status 204 when the same browser tries to reconnect. Only browsers can re-establish the connection by creating a new EventSource object.

This article will explore how to use Server Send Events (SSE) to enable clients to receive automatic updates from the server over an HTTP connection. We will also explore its use and show a practical demonstration of how to use Node.js to send events using a server.

  • Advantages of server sending events
  • Quick Start of Server Send Events
    • Important Tips
  • Advanced server sending event
    • Single and multiple SSE channels
    • Send different data on a single channel
    • Using data identifier
    • Specify retry delay
    • Other event handlers
    • Terminate SSE communication
  • Conclusion

Advantages of server sending events

Web Respond to HTTP messages based on request-response. Your browser issues a URL request and the server returns data. This may cause the browser to make more requests to images, CSS, JavaScript, etc., and the server responds. The server cannot actively send messages to the browser, so how does it indicate that the data has been changed? Fortunately, you can use Server Send Events (SSE) to add features such as live news releases, weather forecasts, and stock prices.

It has always been possible to use standard web technologies to achieve real-time data updates:

  • The 1990s web refreshed using full page or frame/iframe.
  • The 2000s web introduced Ajax, which can use long polling to request data and update the corresponding DOM elements with new information.

Neither of these options are ideal because the browser must trigger a refresh. If it makes requests too often, there will be no data changes, so both the browser and the server will do unnecessary work. If it requests too slowly, it may miss important updates, and the stock price you are following has plummeted!

Server Send Events (SSE) Allows the server to push data to the browser at any time:

  • The browser still makes an initial request to establish the connection.
  • The server returns an event stream response and keeps the connection open.
  • The server can use this connection to send text messages at any time.
  • Incoming data will raise a JavaScript event in the browser. The event handler function parses the data and updates the DOM.

Essentially, SSE is an unlimited data stream. Think of it as downloading an infinitely large file that is downloaded in small pieces that you can intercept and read.

SSE was originally implemented in 2006 and supports this standard in all major browsers. It may not be well known as WebSockets, but the server sends events easier, uses standard HTTP, supports one-way communication, and provides automatic reconnection. This tutorial provides example Node.js code without third-party modules, but SSE can be used in other server-side languages, including PHP.

Quick Start of Server Send Events

The following demonstration implements a Node.js web server that outputs random numbers between 1 and 1000 at random intervals of at least every three seconds.

You can find our Node.js SSE demo here.

This code uses the standard Node.js http and url modules to create a web server and parse URL:

<code class="language-javascript">import http from "node:http";
import url from "node:url";</code>

The server checks for incoming URL requests and reacts when encountering the /random path:

<code class="language-javascript">const port = 8000;

http.createServer(async (req, res) => {

  // 获取 URI 路径
  const uri = url.parse(req.url).pathname;

  // 返回响应
  switch (uri) {
    case "/random":
      sseStart(res);
      sseRandom(res);
      break;
  }

}).listen(port);

console.log(`server running: http://localhost:${port}\n\n`);</code>

It initially responds with the SSE HTTP event stream header:

<code class="language-javascript">// SSE 头
function sseStart(res) {
  res.writeHead(200, {
    Content-Type: "text/event-stream",
    Cache-Control: "no-cache",
    Connection: "keep-alive"
  });
}</code>

Another function then sends a random number and calls itself after the random interval passes:

<code class="language-javascript">// SSE 随机数
function sseRandom(res) {
  res.write("data: " + (Math.floor(Math.random() * 1000) + 1) + "\n\n");
  setTimeout(() => sseRandom(res), Math.random() * 3000);
}</code>

If you run your code locally, you can use cURL in your terminal to test the response:

<code class="language-bash">$> curl -H Accept:text/event-stream http://localhost:8000/random
data: 481

data: 127

data: 975</code>

Press Ctrl | Cmd and C to terminate the request.

Browser's client JavaScript connects to /random URI using the EventSource object constructor:

<code class="language-javascript">// 客户端 JS
const source = new EventSource("/random");</code>

Incoming data triggers the message event handler, where data: the string after it is available in the .data property of the event object:

<code class="language-javascript">source.addEventListener('message', e => {
  console.log('RECEIVED', e.data);
});</code>

Important Tips

  • Like Fetch(), the browser issues standard HTTP requests, so you may need to handle CSP, CORS, and have the option to pass a second { withCredentials: true } parameter to the EventSource constructor to send a cookie.
  • The server must keep a separate res response object for each connected user to send data to it. This is achieved in the above code by passing the value to the closure for the next call.
  • Message data can only be a string in the format data: nn (probably JSON). It is crucial to terminate the carriage return.
  • The server can terminate the SSE response at any time using res.end(), but...
  • When the connection is interrupted, the browser will automatically try to reconnect; there is no need to write your own reconnect code.

Advanced server sends events

SSE does not require more code than shown above, but the following sections discuss other options.

Single and multiple SSE channels

The server can provide any number of SSE channel URLs. For example:

  • /latest/news
  • /latest/weather
  • /latest/stockprice

This may be practical if a single page shows a topic, but not if a single page shows news, weather, and stock prices. In this case, the server must maintain three connections for each user, which can cause memory problems as traffic increases.

Another option is to provide a single endpoint URL, such as /latest, which sends any data type on one communication channel. The browser can indicate the topic of interest in the URL query string, such as /latest?type=news,weather,stockprice, so that the server can limit the SSE response to a specific message.

Send different data on a single channel

Messages from the server can have an associated event: which is passed above the data: line to identify a specific type of information:

<code class="language-javascript">import http from "node:http";
import url from "node:url";</code>

These do not trigger the client's "message" event handler. You must add a handler for each type of event. For example:

<code class="language-javascript">const port = 8000;

http.createServer(async (req, res) => {

  // 获取 URI 路径
  const uri = url.parse(req.url).pathname;

  // 返回响应
  switch (uri) {
    case "/random":
      sseStart(res);
      sseRandom(res);
      break;
  }

}).listen(port);

console.log(`server running: http://localhost:${port}\n\n`);</code>

Using data identifier

The server can also choose to send after the data: line id::

<code class="language-javascript">// SSE 头
function sseStart(res) {
  res.writeHead(200, {
    Content-Type: "text/event-stream",
    Cache-Control: "no-cache",
    Connection: "keep-alive"
  });
}</code>

If the connection is disconnected, the browser sends the last ID back to the server in the Last-Event-ID HTTP header so that the server can resend any missed messages.

The latest ID is also available in the .lastEventId property of the event object of the client:

<code class="language-javascript">// SSE 随机数
function sseRandom(res) {
  res.write("data: " + (Math.floor(Math.random() * 1000) + 1) + "\n\n");
  setTimeout(() => sseRandom(res), Math.random() * 3000);
}</code>

Specify retry delay

Although reconnection is automatic, your server may know that new data is not needed for a specific time period, so there is no need to retain an active communication channel. The server can send a retry: response on itself or as part of the final message, containing the millisecond value. For example:

<code class="language-bash">$> curl -H Accept:text/event-stream http://localhost:8000/random
data: 481

data: 127

data: 975</code>

After receiving it, the browser will abandon the SSE connection and attempt to reconnect after the delay time has passed.

Other event handlers

In addition to "message" and named events, you can also create "open" and "error" handlers in client JavaScript.

When the server connection is established, the "open" event will be triggered. It can be used to run other configuration code or initialize DOM elements:

<code class="language-javascript">// 客户端 JS
const source = new EventSource("/random");</code>

When the server connection fails or terminates, the "error" event is triggered. You can check the .eventPhase property of the event object to see what is going on:

<code class="language-javascript">source.addEventListener('message', e => {
  console.log('RECEIVED', e.data);
});</code>

Remember, there is no need to reconnect: It will happen automatically.

Terminate SSE communication

The browser can terminate SSE communication using the .close() method of the EventSource object. For example:

<code>event: news
data: SSE is great!

event: weather
data: { "temperature": "20C", "wind": "10Kph", "rain": "25%" }

event: stock
data: { "symbol": "AC", "company": "Acme Corp", "price": 123.45, "increase": -1.1 }</code>
The server can terminate the connection by:

  1. Trigger res.end() or send retry: delay, then
  2. Returns HTTP status 204 when the same browser tries to reconnect.

Only browsers can re-establish connections by creating a new EventSource object.

Conclusion

Server-side events provide a way to implement real-time page updates, which may be easier, more practical and lighter than Fetch()-based Ajax polling. The complexity lies in the server side. You must:

  1. Keep all user's active connections in memory, and
  2. Trigger data transfer when changes occur.

But this is completely under your control, and the extension should not be more complex than any other web application.

The only downside is that SSE does not allow you to send messages from the browser to the server (except for the initial connection request). You can use Ajax, but this is too slow for applications like action games. For proper bidirectional communication, you need WebSockets. Please see how to create a live application using WebSockets in Node.js to learn more!

The above is the detailed content of How to Use Server-sent Events in Node.js. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn