Unlock Real‑Time Chat with Server‑Sent Events: From Theory to Code

This article explains how Server‑Sent Events (SSE) enable real‑time, character‑by‑character responses like those seen in ChatGPT, compares SSE with WebSockets, and provides complete server‑side and client‑side code examples for implementing SSE in web applications.

JD Cloud Developers
JD Cloud Developers
JD Cloud Developers
Unlock Real‑Time Chat with Server‑Sent Events: From Theory to Code

Background

With rapid modern technology development, instant interaction becomes crucial. Users expect real‑time, intuitive experiences, especially in chat applications where typing indicators are common.

ChatGPT, an OpenAI product, not only offers powerful natural language processing but also focuses on interaction experience. Its responses appear character by character, mimicking human typing.

Many developers initially assume this effect uses WebSockets, but ChatGPT actually uses Server‑Sent Events (SSE) to push answers incrementally.

Because ChatGPT’s processing is heavy, SSE helps reduce perceived waiting time.

SSE Overview

Server‑Sent Events (SSE) allow a server to send real‑time updates to a web page over HTTP. Compared with WebSockets, SSE is designed for one‑way communication from server to client, making it simpler for certain scenarios.

Main Features

One‑way communication : Server pushes messages; client cannot send via SSE.

Based on HTTP : No new protocol or ports needed.

Automatic reconnection : Browser retries if the connection drops.

Simple format : Text messages separated by double newlines.

Native browser support : Supported by modern browsers except IE and early Edge.

SSE vs WebSockets

Protocol : SSE uses HTTP, simplifying connection; WebSockets use WS/WSS (TCP) and are more flexible.

Communication : SSE is one‑way (server → client); WebSockets are bidirectional.

Configuration : SSE is simple; WebSockets require more complex setup.

Reconnect & tracking : SSE has built‑in reconnection and message tracking; WebSockets usually need manual handling or libraries.

Data format : SSE sends text (can encode binary); WebSockets support both text and raw binary.

Concurrency : SSE may be limited by HTTP version; WebSockets are designed for high concurrency.

Security : SSE works over HTTP/HTTPS; WebSockets can use WSS for stronger encryption.

Browser compatibility : Most modern browsers support SSE; all modern browsers support WebSockets.

Overhead : SSE has higher header overhead per message; WebSockets have low overhead after handshake.

Server‑Side Implementation

To handle SSE, the server must set response headers:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

Example Node.js server that streams JSON data every second:

const http = require('http');
const fs = require('fs');

http.createServer((req, res) => {
  function serveFile(path, type) { /* ... */ }
  function handleSSEConnection() {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive'
    });
    let id = 0;
    const interval = setInterval(() => {
      const message = {
        event: 'customEvent',
        id: id++,
        retry: 30000,
        data: { id, time: new Date().toISOString() }
      };
      for (const key in message) {
        if (key !== 'data') {
          res.write(`${key}: ${message[key]}
`);
        } else {
          res.write(`data: ${JSON.stringify(message.data)}

`);
        }
      }
    }, 1000);
    req.on('close', () => {
      clearInterval(interval);
      res.end();
    });
  }
  // routing logic ...
}).listen(3000);
console.log('Server listening on port 3000');

Client‑Side Practice

Browsers provide the EventSource API. Basic usage:

const eventSource = new EventSource('your_server_url', { withCredentials: true });

eventSource.onopen = () => console.log('Connection opened');
eventSource.onmessage = e => console.log('Received data:', e.data);
eventSource.onerror = e => console.error('Error:', e);

eventSource.addEventListener('customEvent', e => console.log('Custom event:', e.data));

eventSource.close(); // when done

Business Considerations

SSE only supports GET requests; complex parameters must be placed in the URL.

Response format must follow the event/id/retry/data structure.

Data sent over SSE is visible in the browser console, which may expose sensitive information.

To overcome these limits, you can extend SSE with the Fetch API’s streaming capabilities, allowing POST requests and custom data handling. The following example shows a fetchStream function that reads the response body as a stream and processes messages:

/**
 * Convert Uint8Array to string
 */
function Utf8ArrayToStr(array) {
  const decoder = new TextDecoder();
  return decoder.decode(array);
}

/**
 * Establish an SSE‑like connection using fetch and return a Promise of text
 */
const fetchStream = (url, params) => {
  const { onmessage, onclose, ...other } = params;
  return fetch(url, other)
    .then(response => {
      const reader = response.body?.getReader();
      return new ReadableStream({
        start(controller) {
          function push() {
            reader?.read().then(({ done, value }) => {
              if (done) {
                controller.close();
                onclose?.();
                return;
              }
              const decoded = Utf8ArrayToStr(value);
              console.log(decoded);
              onmessage?.(decoded);
              controller.enqueue(value);
              push();
            });
          }
          push();
        }
      });
    })
    .then(stream => new Response(stream, { headers: { 'Content-Type': 'text/html' } }).text();
};

// Example usage
fetchStream('/events', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  credentials: 'include',
  body: JSON.stringify({ boxId: 'exampleBoxId', sessionId: 'exampleSessionId', queryContent: 'exampleQueryContent' }),
  onmessage: res => console.log(res),
  onclose: () => console.log('Connection closed.')
});

Compatibility

Today SSE enjoys broad browser support, except for Internet Explorer.

Conclusion

SSE is a lightweight, HTTP‑based real‑time communication technique ideal for simple, low‑frequency updates such as stock tickers or activity logs. However, its one‑way nature and connection limits make WebSockets a better fit for high‑frequency, bidirectional scenarios. Understanding the strengths and weaknesses of each helps developers choose the right tool for their application.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Web Developmentreal-time communicationServer-Sent EventsSSEEventSource
JD Cloud Developers
Written by

JD Cloud Developers

JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.