Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Handling Client-Side Routing Refreshes in Node.js Express Apps

Tech May 8 3

When a single-page application relies on the browser's History API, direct access or a manual refresh on a route like /products/detail results in a 404. This happens because the server receives the full path, attempts to locate a correpsonding static file or endpoint, and finds nothing. In a traditional hash-based strategy, the fragment identifier (#/products/detail) never reaches the server, so the root document always loads correctly.

To support clean URLs, you need to instruct the server to always serve the application's entry point for any request that does not match an API endpoint or a physical file.

Using a Dedicated Fallback Middleware

The connect-history-api-fallback package elegantly rewrites requests so that the main HTML file is returned where appropriate.

Install the module:

npm install connect-history-api-fallback --save

Integrate it into your Express configuration, ensuring it sits before the static file middleware:

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

const app = express();

// Apply the history API fallback
app.use(historyFallback());

// Serve static assets from the build directory
app.use(express.static(path.join(__dirname, 'build')));

Customizing the Fallback File

If your entry point differs from the standard index.html, supply an index option:

app.use(historyFallback({
  index: '/portal.html'
}));

Rewriting Specific URL Patterns

To redirect certain slugs to dedicated HTML files, leverage the rewrites property:

app.use(historyFallback({
  rewrites: [
    {
      from: /^\/events/,
      to: '/events-dashboard.html'
    },
    {
      from: /^\/blog/,
      to: function(context) {
        return '/blog-landing.html';
      }
    }
  ]
}));

Manual Catch-All Route Approach

Alternatively, you can add a wildcard route that delivers the SPA's HTML shell. This route must be defined after all API and backend routes to avoid intercepting actual data requests.

// All backend API routes should be declared above this line.
// app.use('/api', apiRouter);

app.get('*', (request, response) => {
  response.setHeader('Content-Type', 'text/html; charset=utf-8');
  response.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});

Important: The wildcard path should not conflict with any backend endpoint. Overlapping paths will cause the server to return raw HTML instead of expected JSON data.

Both strategies ensure that clients navigating directly to any valid frontend route receive the application bootstrap, allowing the client-side router to take over rendering seamlessly.

Tags: nodejs

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.