How to Handle Server-Sent Events vs Axios Requests

This article explores the fundamental architectural differences between standard HTTP requests handled by Axios and real-time streaming with Server-Sent Events (SSE). It explains why standard Axios patterns are not suitable for consuming SSE in browser environments, how to properly implement native SSE listeners, and how to handle streaming data with Axios in Node.js environments when standard request-response cycles are not enough.


Standard Requests with Axios

Axios is a promise-based HTTP client designed around the traditional Request-Response cycle. In this model:

  1. The client opens a TCP connection.
  2. The client sends an HTTP request (e.g., GET, POST).
  3. The server processes the request and returns a complete payload with a closing status code (e.g., 200 OK).
  4. The connection is terminated or returned to a connection pool.
import axios from 'axios';

async function fetchUserData() {
  try {
    const response = await axios.get('/api/user/123');
    console.log('Data received:', response.data);
  } catch (error) {
    console.error('Request failed:', error);
  }
}

This pattern is ideal for atomic, stateless transactions, such as retrieving a record, submitting a form, or performing CRUD operations.


What are Server-Sent Events (SSE)?

Server-Sent Events (SSE) establish a persistent, unidirectional stream from the server to the client over standard HTTP.

Unlike standard requests:


Why Axios Is Not Built for Browser-Based SSE

In the browser, Axios relies on XMLHttpRequest (XHR). XHR buffers incoming data by default and does not expose a native event-dispatching mechanism for the text/event-stream format.

While you can technically listen to onDownloadProgress in Axios, it requires manual parsing of SSE frames (handling event:, data:, id:, and \n\n boundaries), and it does not provide automatic reconnection.


The Correct Approach: Native EventSource (Browser)

The standard, most efficient way to handle SSE in the browser is the native EventSource API.

const eventSource = new EventSource('/api/notifications');

// Listen for default message events
eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('New notification:', data);
};

// Listen for custom named events
eventSource.addEventListener('user_update', (event) => {
  const data = JSON.parse(event.data);
  console.log('User update:', data);
});

// Handle connection errors
eventSource.onerror = (error) => {
  console.error('SSE connection error:', error);
  // Native EventSource automatically attempts reconnection
};

// Close connection when no longer needed
function stopListening() {
  eventSource.close();
}

When You Need Custom Headers in the Browser

The native EventSource API does not allow custom HTTP request headers (such as Authorization: Bearer <token>). If headers are required, developers typically use libraries like @microsoft/fetch-event-source rather than Axios, as it wraps the browser's native fetch with streaming support.


Handling SSE with Axios in Node.js

In a Node.js runtime environment, Axios uses the native http module instead of XMLHttpRequest. This allows Axios to receive a readable stream via responseType: 'stream'.

const axios = require('axios');

async function listenToStream() {
  const response = await axios({
    method: 'get',
    url: 'https://api.example.com/stream',
    responseType: 'stream',
    headers: {
      Accept: 'text/event-stream',
      Authorization: 'Bearer YOUR_TOKEN'
    }
  });

  const stream = response.data;

  stream.on('data', (chunk) => {
    const message = chunk.toString();
    console.log('Stream chunk:', message);
    
    // Parse SSE lines manually
    if (message.startsWith('data:')) {
      const dataContent = message.replace(/^data:\s*/, '').trim();
      console.log('Parsed Event Data:', dataContent);
    }
  });

  stream.on('end', () => {
    console.log('Stream ended by server');
  });

  stream.on('error', (err) => {
    console.error('Stream error:', err);
  });
}

listenToStream();

Direct Comparison

Feature Standard Axios Request Server-Sent Events (SSE)
Communication Model Request \(\rightarrow\) Single Response Request \(\rightarrow\) Indefinite Stream
Direction Bidirectional (half-duplex) Unidirectional (Server \(\rightarrow\) Client)
Connection Lifecycle Closes immediately after response Stays open continuously
Content Type application/json, text/html, etc. text/event-stream
Primary Browser Tool Axios / fetch EventSource / fetch-event-source
Auto-Reconnection No (requires manual retry logic) Yes (native to EventSource)
Best Use Case CRUD operations, discrete API calls Live notifications, real-time metrics, LLM text streaming