How to redirect in Next.js from uppercase to lowercase url

I'm trying to redirect visitors from /Contact to /contact.

However, following the instructions in the documentation results in an endless loop of redirects.

This is my attempted solution:

// next.config.js
async redirects() {
    return [
        {
            source: '/Contact',
            destination: '/contact',
            permanent: true
        }
    ]
}

Answer №1

Utilizing Next.JS version 12 or higher, you have the ability to incorporate custom middleware.

To do so, simply create a file named middleware.js within your root directory and input the following code snippet:

import { NextResponse } from 'next/server';

const Middleware = (req) => {
  if (req.nextUrl.pathname === req.nextUrl.pathname.toLowerCase())
    return NextResponse.next();

  return NextResponse.redirect(new URL(req.nextUrl.origin + req.nextUrl.pathname.toLowerCase()));
};

export default Middleware;

Answer №2

If a path does not exist, the following code snippet will automatically redirect it to a lower case path and display a 404 error message if the path is still not found.

import { useEffect } from 'react'
import { useRouter } from 'next/router'
import Error from 'next/error'

export default function ResolveRoute() {
  const router = useRouter()

  useEffect(() => {
    const { pathname } = router;

    if (pathname !== pathname.toLowerCase()) {
      router.push(pathname.toLowerCase())
    }
  },[router])

  return <Error statusCode={404} />
}

To implement this functionality, save the file as "[route].js" in the pages folder of your project. This setup will serve as a universal catch-all for paths that do not have corresponding pages. It will automatically redirect any non-existing paths to their lower case version, and display a 404 error page if needed.

Answer №3

After receiving a helpful suggestion from a Reddit user, I was able to resolve a case sensitivity issue with Next.js routing. The solution involved utilizing the _error.js page component in the following manner:

import { hasUpperCase } from '../lib/string';

...

Error.getInitialProps = ({ asPath, err, res }) => {
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404;

  if (asPath && hasUpperCase(asPath)) {
    res.writeHead(307, { Location: asPath.toLowerCase() });
    res.end();
  }

  return { statusCode };
};

export default Error;

Although I appreciate this approach, I would also be interested in exploring alternatives like using redirects similar to your example.

Answer №4

For those facing this issue, I came across a helpful resource that provides multiple solutions: https://www.youtube.com/watch?v=_vSMITiXAik Solution 1:

  1. Utilize the rewrite function in your next.config.js
    return [
      {
        source: "(c|C)(o|O)(n|N)(t|T)(a|A)(c|C)(t|T)",
        destination: "/Contact", // Be sure to specify the exact page (contact or Contact)
      },
    ];
  },
  1. Implement the _middleware feature: within your pages folder, add a _middleware.ts file.
import { NextRequest, NextResponse } from "next/server";

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname === request.nextUrl.pathname.toLocaleLowerCase())
    return NextResponse.next();
  return NextResponse.redirect(
    `${request.nextUrl.origin}${request.nextUrl.pathname.toLocaleLowerCase()}`
  );
}

By following this solution, you will need to ensure that your page names are all lowercase.

  1. Employ the middleware feature alongside a separate folder for each page.

You must maintain the _middleware.ts and carry out these steps:

  • Create a folder named contact in all lowercase letters.
  • Transfer your page into this folder.
  • Add an index.ts that points to your page with content similar to:
export { default } from "./contact";
  • Rename all your pages using the extension: .page.tsx or page.ts (for TypeScript), and .page.jsx or page.js (for JavaScript).
  • In your next.config.js, include:
    pageExtensions: ["page.tsx", "page.ts"]
    (if using TypeScript) or
    pageExtensions: ["page.jsx", "page.js"]
    (if using JavaScript).

This process should be applied to all pages.

Answer №5

Check out this elegant solution that not only preserves any search or query parameters:

import { NextResponse } from 'next/server';

const Middleware = (req) => {
  if (req.nextUrl.pathname !== req.nextUrl.pathname.toLowerCase()) {
    const url = req.nextUrl.clone()
    url.pathname = url.pathname.toLowerCase()
    return NextResponse.redirect(url)
  }
  return NextResponse.next();
};

export default Middleware;

Answer №6

Although I appreciated Andrew's input, I am leaning more towards a server-side solution rather than a client-side one.

Based on Andrew's feedback, I implemented the following:

import Custom404 from "./404";

export default function CatchAllRoutes({url}) {
    return <Custom404 />
}

export async function getServerSideProps(context) {
    const url = context.query.catch;
    const { res } = context;
    if (url !== url.toLowerCase()) {
        res.writeHead(307, {location: `/${url.toLowerCase()}`}) // 307 is temporary while 308 is permanent, choose your preference here..
        res.end();
    } 
    else {
        context.res.statusCode = 404;
    }
    return { props: { url } }; // Note: You don't need a prop, but the name of function requires one..
}

I saved this code in a file named [catch].js at the root of my pages directory. If the requested URL does not match any page in the project, and it is not already lowercase, it gets converted to lowercase and redirected. Otherwise, if it's a 404, we set the status code to 404 and display the custom404 component.

Answer №7

Upon encountering this issue, I observed that NextJS automatically adds a trailing slash to the paths. Checking the network console in the browser revealed requests with 307 and 308 status codes alternating. Adding a trailing slash to the destination path resulted in numerous requests with a status of 307, but errors persisted.

After appending trailing slashes to both the source and destination paths, the redirection worked correctly:

// next.config.js
async redirects() {
    return [
        {
            source: '/Contact/',
            destination: '/contact/',
            permanent: true
        }
    ]
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Uncovering unseen tags generated by JavaScript on a webpage using Python

I have THIS LINK page that contains javascript. To view the javascript, simply click on show details. How can I extract data from this URL source? Should I use re? Here is what I attempted with re: import urllib import re gdoc = urllib.urlopen('Tha ...

TAILWINDCSS: Is there a way to prevent the page from shrinking beyond a certain breakpoint? Take a look at the images provided for visual

Currently, the page can be minimized to a very narrow width as depicted in the image below. https://i.stack.imgur.com/gZqvV.png Is there a way to specify the smallest breakpoint screen size that the page can shrink to this particular width? https://i.sta ...

Accessing a model's field within an Ember.js each loop

Here is the code for a route that I am working on: Calendar.DateIndexRoute = Ember.Route.extend({ model: function(data) { return {arr:getCalendar(data), activeYear: data.year, activeMonthNumber: data.month, activeDay: data.da ...

Transforming the AngularJS $http GET method to OPTION and including custom headers

var users= $resource('http://myapp.herokuapp.com/users', {}); users.get(); The change in the HTTP GET method to OPTION occurred after implementing a header method. var users= $resource('http://myapp.herokuapp.com/users', {}, { get ...

stop the leakage of CSS and JS from the subtree to the document through the inverse shadow DOM mechanism

My page contains dynamic HTML content that I want to incorporate. The dynamic content consists of only HTML and CSS, without any JavaScript. However, I have some custom global CSS styles and JS logic that need to be implemented along with this dynamic con ...

How can I prevent clearQueue() from removing future queues?

In my code, I have a button that triggers the showing of a div in 500ms when clicked. After the div is shown, a shake class is added to it after another 500ms. The shake class is then removed after 2 seconds using the delay function. However, if the user c ...

Unable to authenticate the initial certificate with Node

Out of the blue, my Node environments are experiencing issues with installing packages and freezing at idealTree:my-app : sill idealTree buildDeps Although I attempted to fix it by using npm config set registry http://registry.npmjs.org/ --global, it didn ...

Passing Node.js MySQL query results to the next function within an async.waterfall workflow

In my node.js code using express, I have set up a route to request data from a mysql database. My goal is to pass the returned JSON in tabular form to another function to restructure it into a hierarchy type JSON. I have individually tested the script to ...

I am encountering a JQuery syntax error while using Bootstrap 3 button-dropdown links

I'm trying to replicate the example found here in order to create a similar markup: <div class="btn-group"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> ...

I am facing an issue with TypeScript as it is preventing me from passing the prop in React and Zustand

interface ArticuloCompra { id: string; cantidad: number; titulo: string; precio: number; descuento: number; descripcion: string; imagen: string; } const enviarComprasUsuarios = ({ grupos, }: { grupos: { [key: string]: ArticuloCompra & ...

I am looking to modify the highlighted table cell whenever the value within it changes

I am currently working on a small project related to the Stock Market. In this project, I need to dynamically change the style of the td element based on data fluctuations - green highlight for an increase and red highlight for a decrease. In the provid ...

Filter the output from a function that has the ability to produce a Promise returning a boolean value or a

I can't help but wonder if anyone has encountered this issue before. Prior to this, my EventHandler structure looked like: export interface EventHandler { name: string; canHandleEvent(event: EventEntity): boolean; handleEvent(event: EventEntity ...

Rotate the circular border in a clockwise direction when clicked

I have successfully designed a heart icon using SVG that can be filled with color upon clicking. Now, I am looking to add an outer circle animation that rotates clockwise around the heart as it is being created. Currently, the circle only spins in the code ...

Constructing and rendering PDFs with c# and React

I am currently working on a project involving the generation of a customized PDF file based on user input and database information. I am seeking guidance on executing this project and deciding on which frameworks to utilize. The project is divided into thr ...

Checkbox Hierarchy: Children marked as either Checked or Unchecked based on parent selection

Hello, I have a form that contains nested checkboxes on three levels. Using jQuery, I am trying to check/uncheck all the children when I check a parent level... and if any of the children are unchecked, uncheck the parent as well. I have attempted this m ...

Show the current temperature data retrieved from the weather API

I'm trying to figure out what's causing the issue with the temperature not displaying. Can anyone help me identify and fix the error? <script type="text/javascript"> $.ajax({ url: 'https://api.weather.gov/gridpoints/EWX ...

When combining CSS grids, nesting them can sometimes cause issues with the height layout

Check out the code on jsFiddle .component-container { width: 800px; height: 200px; background-color: lightyellow; border: 1px solid red; padding: 10px; overflow: hidden; } .component-container .grid-container-1 { display: grid; grid-tem ...

A guide to implementing react-hook-form in conjunction with form actions

Having trouble with this code as it's not performing validation upon submission? The login process is coded here using Zod for validation and React Hook Form for managing the form. However, the validation seems to be skipping, leading to a direct call ...

Rendering a component within an asynchronous function using Next.js

I'm currently learning Next.js and attempting to iterate over a collection of items in an array to pass them into a card component. However, I am facing an issue where the Card component is not rendering on the page. When I place the Card element betw ...

Why won't the function activate on the initial click within the jQuery tabs?

When creating a UI with tabs, each tab contains a separate form. I have noticed that when I click on the tabs, all form save functions are called. However, if I fill out the first tab form and then click on the second tab, refresh the page, and go back t ...