Axios Handling of HTTP 304 Not Modified

When the Axios HTTP client receives an HTTP 304 Not Modified response, its behavior depends on default status validation rules and the runtime environment (browser vs. Node.js). By default, Axios treats a 304 status as an error and rejects the request promise because it only considers 2xx status codes successful. This article details why this rejection occurs, how the execution environment impacts the response, and how to properly configure Axios to handle 304 statuses.

Default Status Validation in Axios

Axios determines whether a promise should resolve or reject using the validateStatus configuration option. By default, validateStatus is defined as:

validateStatus: function (status) {
  return status >= 200 && status < 300;
}

Because an HTTP 304 code falls outside the 200–299 range, Axios creates an AxiosError and rejects the promise. If an application does not intercept or catch this error, the request fails, even though HTTP 304 is a standard response indicating that a cached version of the resource is still valid.

Environment Differences: Browser vs. Node.js

The runtime environment plays a significant role in how a 304 response is surfaced to your code:

  • In the Browser: The browser's native networking layer (XMLHttpRequest or Fetch API) handles caching automatically. When conditional headers like If-None-Match (ETag) or If-Modified-Since are sent, the browser intercepts the server's 304 response, retrieves the content from its local cache, and passes a 200 OK status with the cached body to Axios. Consequently, developers rarely encounter an unhandled 304 in browser environments unless native caching is manually disabled.
  • In Node.js: Node.js lacks a built-in HTTP cache. When Axios makes a request that returns a 304 status, the Node.js HTTP adapter receives the raw 304 response directly from the server. Because there is no native cache to resolve the payload, Axios immediately rejects the promise based on the default validateStatus check.

How to Handle HTTP 304 in Axios

To prevent Axios from throwing an error upon encountering a 304 status, you can customize the validateStatus function in your request configuration or global Axios instance:

const axios = require('axios');

axios.get('https://api.example.com/data', {
  headers: {
    'If-None-Match': '"etag-value-12345"'
  },
  validateStatus: function (status) {
    return (status >= 200 && status < 300) || status === 304;
  }
})
.then(response => {
  if (response.status === 304) {
    // Resource has not changed; use application-level cached data
    console.log('Resource not modified. Using cached data.');
  } else {
    // Fresh data received
    console.log('Received fresh data:', response.data);
  }
})
.catch(error => {
  console.error('Request failed:', error);
});

Managing Cached Payloads

Accepting an HTTP 304 status via validateStatus does not automatically populate response.data. A 304 response typically contains empty response headers and no body. When working in server-side environments like Node.js, your application architecture must maintain its own local cache layer (such as Redis, an in-memory store, or an Axios caching interceptor) to serve the stored data when a 304 status is returned.