Next.js Discord

Discord Forum

Stumped on middleware & subdomains

Unanswered
African Slender-snouted Crocodil… posted this in #help-forum
Open in Discord
African Slender-snouted CrocodileOP
I have a stripped down page router app, In the project, I have static pages that depend on both the subdomain/custom domain and a slug. I am using middleware to rewrite incoming requests from sub.domain.com/to/[slug] into sub.domain.com/_sites/sub.domain.com/[slug]. Then in /pages/_sites/[site]/[slug].ts, I have a getStaticProps I generate some static content logging out the site, slug, and time.

The issue I see is that if I use the same slug and different subdomains, the content for the first subdomain will always show up.

When I look at the logs, the middleware runs twice for every request. Once with the original url and again with the original url but with site and slug as searchParams. The searchParams are always of the first generated page, so the site param is wrong.

Example Logs:
<us.hostname.com/to/test>
Middleware - Original URL: us.hostname.com/to/test
Middleware - Rewrite URL: us.hostname.com/_sites/us.hostname.com/test
Middleware - Original URL: us.hostname.com/to/test?site=us.hostname.com&slug=test
Middleware - Rewrite URL: us.hostname.com/_sites/us.hostname.com/test
<eu.hostname.com/to/test>
Middleware - Original URL: eu.hostname.com/to/test
Middleware - Rewrite URL: eu.hostname.com/_sites/eu.hostname.com/test
Middleware - Original URL: eu.hostname.com/to/test?site=us.hostname.com&slug=test
Middleware - Rewrite URL: eu.hostname.com/_sites/eu.hostname.com/test


I'm not sure why the middleware is called twice, and with incorrect searchParams, and how to stop it...

2 Replies

African Slender-snouted CrocodileOP
middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export const config = {
  matcher: ['/', '/to/:slug*']
};

export default function middleware(req: NextRequest) {
  const url = req.nextUrl;
  const hostname = url.host;
  
  const querySlug = url.searchParams.get('slug');
  const pathSlug = url.pathname.split('/to/').at(1);
  const slug = querySlug ?? pathSlug ?? ''

  if (!slug) {
    return NextResponse.redirect('https://google.com');
  }

  const newPath = `/_sites/${hostname}/${slug}`;

  const rewriteUrl = new URL(newPath, url.origin);

  console.log('Middleware - Original URL:', url.toString());
  console.log('Middleware - Rewrite URL:', rewriteUrl.toString());

  return NextResponse.rewrite(rewriteUrl);
}
pages/_sites/[site]/[slug].tsx
import TestPage, { Props } from '@/components/TestPage';

import type { GetStaticProps, GetStaticPaths } from 'next';

export const getStaticPaths: GetStaticPaths = async () => {
  // generate no slugs at build, but cache them after first visit
  return {
    paths: [],
    fallback: 'blocking'
  };
};

export const getStaticProps: GetStaticProps<Props> = async ({ params }) => {
  if (!params) throw new Error('No path parameters found');

  const time = Date.now();
  const { site, slug } = params;
  console.log('getStaticProps', 'site', site);
  console.log('getStaticProps', 'slug', slug);
  console.log('getStaticProps', 'time', time);

  return { props: { slug, site, time } as Props };
};

export default TestPage;


/components/TestPage.tsx
import { useRouter } from 'next/router';
import { getRegionMeta } from '@/utils/regions';

export type Props = {
  site: string;
  slug: string;
  time: number;
};

export default function TestPage({ site, slug, time }: Props) {
  const router = useRouter();
  const queryParams = router.query;
  // just looks up the region (us, ca, eu, au) based on the hostname
  const { region, apiUrl } = getRegionMeta(site);

  return (
    <>
      <div>
        <p>Date: {new Date(time).toLocaleDateString()}</p>
        <p>Time: {new Date(time).toLocaleTimeString()}</p>
        <p>Site: {site}</p>
        <p>Slug: {slug}</p>
        <p>Region: {region}</p>
        <p>API: {apiUrl}</p>
        <p>Params:</p>
        <pre>{JSON.stringify(queryParams, null, 2)}</pre>
      </div>
    </>
  );
}