404 error when trying to access deep-linked routes

Loading

If you’re facing a 404 error when accessing deep-linked routes, the issue is usually related to how your frontend framework (React, Angular, Vue) and backend server (Node.js, Express, Nginx, Apache) handle routing.

Let’s go step by step to diagnose and fix this issue based on different environments.


Step 1: Understanding Why Deep Linking Fails

When you navigate within a Single Page Application (SPA), the JavaScript framework (React, Angular, Vue) handles routing internally. However, when you refresh a deep-linked page (/dashboard, /profile, /user/123), the browser requests the URL from the server, which might not have a matching backend route, resulting in a 404 error.

Common Causes

  1. Static file server doesn’t handle SPA routes
  2. Backend doesn’t redirect unknown routes to the frontend
  3. Incorrect route configurations in React Router, Angular Router, or Vue Router
  4. Hosting configuration issues (Nginx, Apache, Vercel, Firebase, etc.)

Step 2: Fixing the Issue Based on Your Setup

Fix 1: Handling Deep Links in React (React Router – Frontend Fix)

If you’re using React Router for navigation, ensure that the BrowserRouter is properly configured.

Solution: Use <BrowserRouter> and Ensure Correct Route Setup

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import Dashboard from './pages/Dashboard';
import NotFound from './pages/NotFound';

function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="*" element={<NotFound />} /> {/* Catch-all route */}
</Routes>
</Router>
);
}

export default App;

🔹 Why This Works?

  • The wildcard * ensures unmatched routes don’t return a 404 page.
  • React Router handles the routes inside the app.

Solution: Add a Redirect Rule for React (Nginx, Apache, or Firebase Hosting)

If you’re using Nginx, update your configuration (nginx.conf):

location / {
root /var/www/html;
index index.html;
try_files $uri /index.html;
}

Explanation:

  • try_files $uri /index.html; ensures that if a deep link is accessed, the request is redirected to index.html, where React Router handles it.

For Apache, update .htaccess:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>

For Firebase Hosting, update firebase.json:

jsonCopyEdit"rewrites": [
    {
      "source": "**",
      "destination": "/index.html"
    }
]

Fix 2: Handling Deep Links in Angular (Angular Router Fix)

By default, Angular apps use client-side routing, which breaks when you refresh a deep link.

Solution: Enable HTML5 Routing and Redirect Unknown Routes

1️⃣ Modify app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { DashboardComponent } from './dashboard/dashboard.component';

const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'dashboard', component: DashboardComponent },
{ path: '**', redirectTo: '/' }, // Redirect unknown routes to Home
];

@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: false })],
exports: [RouterModule]
})
export class AppRoutingModule {}

🔹 Why This Works?

  • The useHash: false ensures clean URLs without # fragments.
  • The wildcard ** redirects unknown routes.

2️⃣ Update server.js (Express.js Backend Serving Angular App)
If you’re using an Express.js backend:

const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(__dirname + '/dist/my-angular-app'));

app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '/dist/my-angular-app/index.html'));
});

app.listen(8080, () => {
console.log('Server started on port 8080');
});

🔹 Why This Works?

  • It ensures all deep-link requests serve index.html, allowing Angular Router to handle them.

Fix 3: Handling Deep Links in Vue.js (Vue Router Fix)

For Vue.js with Vue Router, you need to configure the router and backend correctly.

Solution: Use mode: "history" and Handle Fallbacks

Modify router/index.js:

import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import Dashboard from '../views/Dashboard.vue';

const routes = [
{ path: '/', component: Home },
{ path: '/dashboard', component: Dashboard },
{ path: '/:pathMatch(.*)*', redirect: '/' } // Redirect unknown routes
];

const router = createRouter({
history: createWebHistory(),
routes
});

export default router;

🔹 Why This Works?

  • createWebHistory() enables history mode (clean URLs).
  • /:pathMatch(.*)* redirects unknown routes.

Solution: Update Backend (Node.js/Express.js)

const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'dist')));

app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});

app.listen(5000, () => console.log('Server running on port 5000'));

Fix 4: Handling Deep Links in Next.js (Server-Side Rendering – SSR)

Next.js should automatically handle deep links unless there’s a misconfiguration.

Solution: Ensure You Have a [...slug].js Catch-All Route

If using pages routing, create pages/[[...slug]].js:

import { useRouter } from 'next/router';

export default function CatchAllPage() {
const router = useRouter();
return <h1>Dynamic Route: {router.query.slug}</h1>;
}

If using App Router (Next.js 13+), create app/[...slug]/page.js:

export default function Page({ params }) {
return <h1>Dynamic Route: {params.slug}</h1>;
}

Solution: Fix next.config.js if Needed

module.exports = {
async rewrites() {
return [
{
source: '/:path*',
destination: '/index.html'
}
];
}
};

Step 3: Debugging 404 Errors

Check Browser DevTools Console (F12)

  • Look for network errors when accessing deep links.

Check Network Requests in DevTools

  • Open Network Tab → Look for requests returning 404.

Manually Test Server Response
Run:

curl -I http://localhost:5000/dashboard

If it returns 404, backend routing is not set up properly.

Leave a Reply

Your email address will not be published. Required fields are marked *