Connect History API Fallback Middleware

2.0.0 · active · verified Tue Apr 21

connect-history-api-fallback is a robust middleware designed for Single Page Applications (SPAs) leveraging the HTML5 History API. It addresses the common challenge where direct access to client-side routes (e.g., `/about` or `/users/123`) or page refreshes result in a 404 "Not Found" error from the web server, as these paths do not correspond to physical files. The middleware intercepts such requests, identifies those that accept `text/html` and are not direct file requests (by default, paths containing a dot), and then rewrites the request URL to a specified index file, typically `/index.html`. This allows the SPA's client-side router to take over and render the correct view. The current stable version is 2.0.0. While there isn't a strict release cadence, updates generally address compatibility, performance, or new configuration options. Key differentiators include its configurable `index` path, powerful `rewrites` option supporting both static strings and dynamic functions based on request context, and fine-grained control over accepted HTML headers and dot-file handling. It seamlessly integrates with Connect and Express-based Node.js servers.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to integrate `connect-history-api-fallback` with an Express server to handle client-side routing for a Single Page Application (SPA). It correctly places the middleware to serve static assets while ensuring that direct URL access or page refreshes on SPA routes gracefully fall back to `index.html`.

const express = require('express');
const history = require('connect-history-api-fallback');
const path = require('path');
const app = express();

// Create a simple 'public' directory with an 'index.html' for this example
// You would typically have a build process generating these files.
// For demonstration, ensure you have a 'public' directory with an index.html.
// Example public/index.html content:
// <!DOCTYPE html>
// <html lang="en">
// <head><meta charset="UTF-8"><title>SPA</title></head>
// <body><h1>Welcome to SPA!</h1><p>Path: <span id="path"></span></p>
// <script>document.getElementById('path').innerText = window.location.pathname;</script>
// <nav><a href="/">Home</a> | <a href="/about">About</a> | <a href="/users/1">User</a></nav></body>
// </html>

// 1. Serve your static assets (like JS, CSS, images) first.
// This ensures that actual files are served directly and not rewritten.
app.use(express.static(path.join(__dirname, 'public')));

// 2. Use the history API fallback middleware.
// This middleware should come AFTER your static file server
// but BEFORE any other catch-all routes.
app.use(history({
  // verbose: true, // Uncomment to log rewrite actions to the console
  index: '/index.html', // Default in most cases, but good to be explicit
  htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] // Default in v2.0.0+
}));

// 3. Serve static assets again after the history fallback.
// This is crucial: after a rewrite to `/index.html`, this `express.static` call
// will actually serve the `index.html` file from your 'public' directory.
app.use(express.static(path.join(__dirname, 'public')));

// Optional: A final catch-all for anything not handled (e.g., actual 404s for non-SPA routes)
app.get('*', (req, res) => {
  res.status(404).send('Custom 404 - Resource Not Found on Server.');
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server listening on http://localhost:${PORT}`);
  console.log('Navigate to /some-spa-route, then refresh the page.');
  console.log('It should still serve index.html, handled by your client-side router.');
});

view raw JSON →