You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中间件重复请求未触发,切换语言后路由语言回退问题

多语言Next.js项目路由切换后语言回退问题解决

项目背景

基于Next.js App Router创建多语言项目,路由格式要求为/en/...或/vi/...。为避免在所有组件(包括Link)中重复使用useParams拼接语言前缀,通过middleware.ts实现自动重定向,只需写<Link href='/page'>Page</Link>即可自动跳转到带语言前缀的路由。

原冗余写法示例:

const {lang} = useParams()

return <>
  <Link href={`/${lang}/page`}>Page</Link>
</>

中间件实现代码

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

export function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname;
  const getLangInPathname = pathname.split("/")[1];

  if (getLangInPathname !== "en" && getLangInPathname !== "vi") {
    let lang = request.cookies.get("_lang")?.value || "en";
    return NextResponse.redirect(new URL(`/${lang}${pathname}`, request.url));
  }
}

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

问题现象

当前语言为vi时,通过SwitchLang组件切换到en后,进行路由跳转,语言会自动变回vi;多次切换后问题依旧。查看浏览器网络面板发现路由请求未发送到服务器,middleware未执行。

切换语言组件代码:

"use client";

import Cookies from "js-cookie";
import { useParams, usePathname, useRouter } from "next/navigation";
import { useEffect } from "react";

function SwitchLang() {
  const { lang } = useParams();
  const pathname = usePathname();
  const router = useRouter();

  useEffect(() => {
    Cookies.set("_lang", lang);
  }, [lang]);

  const handleChangeLang = (lang: string) => {
    Cookies.set("_lang", lang);
    router.push(pathname.replace(pathname.slice(1, 3), lang));
  };

  return (
    <div>
      <span
        onClick={() => handleChangeLang("en")}
        style={{
          fontSize: lang === "en" ? 25 : 14,
        }}
      >
        en
      </span>
      <br />
      <span
        onClick={() => handleChangeLang("vi")}
        style={{
          fontSize: lang === "vi" ? 25 : 14,
        }}
      >
        vi
      </span>
    </div>
  );
}

export default SwitchLang;

已尝试的无效方案

在next.config.js中添加禁用缓存配置,无效果:

module.exports = {
  headers: () => [
    {
      source: '/:path*',
      headers: [
        {
          key: 'Cache-Control',
          value: 'no-store',
        },
      ],
    },
  ],
}

解决方案

问题根源是Next.js App Router的客户端路由缓存机制——切换语言后,客户端仍缓存旧语言版本的路由,导致跳转时直接使用缓存内容,未触发中间件。需从以下两点修复:

1. 修改语言切换逻辑,强制刷新客户端缓存

在handleChangeLang中,构造完整新路由后调用router.refresh(),确保客户端缓存更新:

const handleChangeLang = (lang: string) => {
  Cookies.set("_lang", lang);
  // 构造新的完整路径,替换原语言前缀
  const newPath = `/${lang}${pathname.slice(3)}`;
  router.push(newPath);
  // 强制刷新客户端缓存,确保新语言路由生效
  router.refresh();
};

2. 增强中间件逻辑,校验路径与Cookie语言一致性

当前中间件仅在路径无合法语言前缀时重定向,需补充路径语言与Cookie语言不一致时也触发重定向的逻辑,确保服务器端能修正路由:

export function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname;
  const getLangInPathname = pathname.split("/")[1];
  const cookieLang = request.cookies.get("_lang")?.value || "en";

  // 两种情况触发重定向:
  // 1. 路径无合法语言前缀
  // 2. 路径语言与Cookie中存储的语言不一致
  if (getLangInPathname !== "en" && getLangInPathname !== "vi") {
    return NextResponse.redirect(new URL(`/${cookieLang}${pathname}`, request.url));
  } else if (getLangInPathname !== cookieLang) {
    const newPath = pathname.replace(`/${getLangInPathname}`, `/${cookieLang}`);
    return NextResponse.redirect(new URL(newPath, request.url));
  }
}

3. 可选优化:禁用Link预取(按需)

若仍存在缓存问题,可在Link组件上添加prefetch={false},避免提前缓存旧语言路由:

<Link href='/page' prefetch={false}>Page</Link>

通过以上修改,切换语言后跳转路由时会触发中间件校验Cookie与路径语言的一致性,同时强制刷新客户端缓存,彻底解决语言回退问题。

内容的提问来源于stack exchange,提问作者kan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 09:15:03