Core points
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
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:
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:
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:
import http from "node:http"; import url from "node:url";
The server checks for incoming URL requests and reacts when encountering the /random path:
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`);
It initially responds with the SSE HTTP event stream header:
// SSE 头 function sseStart(res) { res.writeHead(200, { Content-Type: "text/event-stream", Cache-Control: "no-cache", Connection: "keep-alive" }); }
Another function then sends a random number and calls itself after the random interval passes:
// SSE 随机数 function sseRandom(res) { res.write("data: " + (Math.floor(Math.random() * 1000) + 1) + "\n\n"); setTimeout(() => sseRandom(res), Math.random() * 3000); }
If you run your code locally, you can use cURL in your terminal to test the response:
$> curl -H Accept:text/event-stream http://localhost:8000/random data: 481 data: 127 data: 975
Press Ctrl | Cmd and C to terminate the request.
Browser's client JavaScript connects to /random URI using the EventSource object constructor:
// 客户端 JS const source = new EventSource("/random");
Incoming data triggers the message event handler, where data: the string after it is available in the .data property of the event object:
source.addEventListener('message', e => { console.log('RECEIVED', e.data); });
{ withCredentials: true }
parameter to the EventSource constructor to send a cookie. Advanced server sends events
SSE does not require more code than shown above, but the following sections discuss other options.
The server can provide any number of SSE channel URLs. For example:
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.
Messages from the server can have an associated event:
which is passed above the data:
line to identify a specific type of information:
import http from "node:http"; import url from "node:url";
These do not trigger the client's "message" event handler. You must add a handler for each type of event. For example:
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`);
The server can also choose to send after the data:
line id:
:
// SSE 头 function sseStart(res) { res.writeHead(200, { Content-Type: "text/event-stream", Cache-Control: "no-cache", Connection: "keep-alive" }); }
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:
// SSE 随机数 function sseRandom(res) { res.write("data: " + (Math.floor(Math.random() * 1000) + 1) + "\n\n"); setTimeout(() => sseRandom(res), Math.random() * 3000); }
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:
$> curl -H Accept:text/event-stream http://localhost:8000/random data: 481 data: 127 data: 975
After receiving it, the browser will abandon the SSE connection and attempt to reconnect after the delay time has passed.
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:
// 客户端 JS const source = new EventSource("/random");
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:
source.addEventListener('message', e => { console.log('RECEIVED', e.data); });
Remember, there is no need to reconnect: It will happen automatically.
Terminate SSE communication
<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>
retry:
delay, then 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:
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!