Next.js(Pages Router) v16에서 URL의 로케일 매개변수를 검증하는 방법

지원되지 않는 로케일 코드를 우아하게 처리하기

문제

로케일 코드가 URL 구조의 일부가 되면, 검증이 필요한 사용자 입력으로 변환됩니다. 방문자는 유효한 로케일인 /en/about과 마찬가지로 /xx/about 또는 /gibberish/contact를 쉽게 입력할 수 있습니다. 검증이 없으면 애플리케이션이 충돌하거나, 깨진 콘텐츠를 표시하거나, 혼란스러운 오류 메시지를 보여줄 수 있습니다. 유효하지 않은 로케일 URL을 접한 사용자들은 유효한 로케일로 리디렉션되거나 무엇이 잘못되었는지 이해할 수 있는 적절한 "찾을 수 없음" 응답을 통해 명확한 경로를 필요로 합니다.

해결책

요청이 페이지 컴포넌트에 도달하기 전에 지원되는 로케일 목록에 대해 들어오는 로케일 매개변수를 검증합니다. Next.js 미들웨어를 사용하여 요청을 가로채고, URL의 로케일이 지원되는 값과 일치하는지 확인한 후 적절하게 응답합니다. 유효하지 않은 로케일의 경우, 사용자를 기본 로케일로 리디렉션하거나 404 페이지를 표시하도록 요청을 다시 작성합니다. 이렇게 하면 유효한 로케일 코드만 콘텐츠를 렌더링하는 데 진행되고, 유효하지 않은 코드는 사용자 경험을 해치지 않고 우아하게 처리됩니다.

단계

1. Next.js 구성에서 지원되는 로케일 정의하기

애플리케이션이 지원하는 로케일과 기본 로케일로 사용할 로케일을 선언하기 위해 next.config.js에서 i18n 설정을 구성합니다.

module.exports = {
  i18n: {
    locales: ["en", "fr", "de"],
    defaultLocale: "en",
    localeDetection: false,
  },
};

localeDetection을 false로 설정하면 브라우저 환경설정에 따른 자동 리디렉션을 방지하여 로케일 처리에 대한 완전한 제어권을 얻을 수 있습니다.

2. 로케일 매개변수를 검증하는 미들웨어 생성하기

프로젝트의 루트 또는 src 폴더를 사용하는 경우 해당 폴더 내에 middleware.ts 파일을 생성합니다.

import { NextRequest, NextResponse } from "next/server";

const SUPPORTED_LOCALES = ["en", "fr", "de"];
const DEFAULT_LOCALE = "en";

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  const pathnameHasLocale = SUPPORTED_LOCALES.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`,
  );

  if (!pathnameHasLocale) {
    return;
  }

  const localeInPath = pathname.split("/")[1];

  if (!SUPPORTED_LOCALES.includes(localeInPath)) {
    const url = request.nextUrl.clone();
    url.pathname = pathname.replace(`/${localeInPath}`, `/${DEFAULT_LOCALE}`);
    return NextResponse.redirect(url);
  }
}

export const config = {
  matcher: ["/((?!_next|api|favicon.ico|.*\\..*).*)"],
};

이 미들웨어는 URL 경로에서 로케일을 추출하고, 지원되는 로케일 배열과 대조하여 확인한 다음, 유효하지 않은 로케일을 경로의 나머지 부분을 유지하면서 기본 로케일로 리디렉션합니다.

3. 유효하지 않은 로케일을 404 응답으로 처리하기

리디렉션 대신 404 페이지를 표시하는 것을 선호한다면, 요청을 커스텀 404 페이지로 재작성하세요.

import { NextRequest, NextResponse } from "next/server";

const SUPPORTED_LOCALES = ["en", "fr", "de"];

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  const pathnameHasLocale = SUPPORTED_LOCALES.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`,
  );

  if (!pathnameHasLocale) {
    return;
  }

  const localeInPath = pathname.split("/")[1];

  if (!SUPPORTED_LOCALES.includes(localeInPath)) {
    const url = request.nextUrl.clone();
    url.pathname = "/404";
    return NextResponse.rewrite(url);
  }
}

export const config = {
  matcher: ["/((?!_next|api|favicon.ico|.*\\..*).*)"],
};

빌드 시 정적으로 생성되는 pages/404.js에 커스텀 404 페이지를 만드세요.

4. 커스텀 404 페이지 만들기

export default function Custom404() {
  return (
    <div>
      <h1>404 - 페이지를 찾을 수 없습니다</h1>
      <p>찾으시는 페이지가 존재하지 않습니다.</p>
    </div>
  );
}

이 페이지는 미들웨어가 유효하지 않은 로케일 요청을 재작성할 때 표시되며, 사용자에게 요청한 URL이 사용 불가능하다는 명확한 메시지를 제공합니다.