项目根目录Middleware下Shallow路由跳转失效问题求助
Shallow路由导航失效:地址栏变更但页面未更新
问题现象
在Next.js项目中使用shallow选项导航时,浏览器地址栏链接已变更,但页面内容未更新。涉及场景:
- 侧边栏通过
NextLink添加shallow属性导航 - 按钮点击调用
router.push并配置shallow: true导航
相关代码
NextLink导航代码
<NextLink href='/dashboard' passHref shallow>Dashboard</NextLink> <NextLink href='/users' passHref shallow>Users</NextLink> <NextLink href='/users' passHref shallow>Posts</NextLink>
router.push导航代码
<Button onClick={() => router.push('/dashboard', {}, { shallow: true })}>Dashboard</Button>
Middleware代码(./src/middleware.ts)
import { NextResponse, NextMiddleware } from 'next/server'; const PUBLIC_FILE = /\.(.*)$/; export const middleware: NextMiddleware = (req) => { const acceptLanguage = req?.headers?.get('accept-language') && req?.headers?.get('accept-language')?.slice(0, 2); if ( req.nextUrl.pathname.startsWith('/_next') || req.nextUrl.pathname.includes('/api/') || PUBLIC_FILE.test(req.nextUrl.pathname) ) { return; } if (req.nextUrl.locale === 'default') { const newUrl = req.nextUrl.clone(); newUrl.locale = acceptLanguage || 'en'; return NextResponse.redirect(newUrl); } };
依赖版本
- "next": "^12.3.4"
- "next-translate": "^2.0.4"
- "react": "^17.0.2"
- "react-dom": "^17.0.2"
原因分析
- Shallow路由适用场景误解:Next.js的
shallow路由仅支持同一页面路由下的查询参数/哈希变更(如/dashboard?tab=1→/dashboard?tab=2)。若跳转到不同路由路径(如/dashboard→/users),shallow选项完全无效,因为这属于跨页面路由切换,必须触发完整导航流程。 - Middleware重定向打破客户端导航:即使是符合shallow场景的同路由导航,当前Middleware会对默认locale路径触发服务器端重定向。而shallow路由依赖纯客户端导航,一旦触发服务器端重定向,客户端shallow逻辑会被中断,导致页面无法正常更新。
解决方案
1. 修正Shallow路由的使用
若跳转到不同路由路径,直接移除shallow属性(对跨路由导航无效):
<NextLink href='/dashboard' passHref>Dashboard</NextLink> <NextLink href='/users' passHref>Users</NextLink> <NextLink href='/users' passHref>Posts</NextLink>
2. 修改Middleware避免中断客户端导航
在Middleware中判断是否为客户端发起的导航(通过x-nextjs-data请求头),若是则跳过重定向逻辑,保留shallow路由的客户端行为:
import { NextResponse, NextMiddleware } from 'next/server'; const PUBLIC_FILE = /\.(.*)$/; export const middleware: NextMiddleware = (req) => { const acceptLanguage = req?.headers?.get('accept-language')?.slice(0, 2); if ( req.nextUrl.pathname.startsWith('/_next') || req.nextUrl.pathname.includes('/api/') || PUBLIC_FILE.test(req.nextUrl.pathname) ) { return; } // 判断是否为客户端导航(Next.js客户端导航会携带x-nextjs-data头) const isClientNavigation = req.headers.get('x-nextjs-data') !== null; if (req.nextUrl.locale === 'default') { // 客户端导航时跳过重定向,保留shallow路由行为 if (isClientNavigation) { return NextResponse.next(); } const newUrl = req.nextUrl.clone(); newUrl.locale = acceptLanguage || 'en'; return NextResponse.redirect(newUrl); } };
内容的提问来源于stack exchange,提问作者IncognitoUser
相关产品推荐
相关产品推荐

