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
相关产品推荐
相关产品推荐

