Next.js中基于header参数的Rewrites重写规则不生效问题
问题描述
通过Header类型匹配规则实现移动端/桌面端页面路由重写(切换访问目标路径)时功能未生效:浏览器响应头中可以看到自定义设置的x-rewrite字段,但next.config.js中配置的Rewrites重写规则始终不触发。
复现代码
pages/_middleware.ts
import { NextRequest, NextResponse } from 'next/server'; const isMobile = (userAgent: string) => /iPhone|iPad|iPod|Android/i.test(userAgent); const propName = 'x-rewrite'; enum Device { desktop = 'no', mobile = 'yes', } export function middleware(req: NextRequest) { const userAgent = req.headers.get('user-agent'); const res = NextResponse.next(); if (userAgent) { if (isMobile(userAgent)) { res.headers.set(propName, Device.mobile); console.log(res.headers, 'res'); return res; } else { res.headers.set(propName, Device.desktop); return res; } } }
next.config.js 重写配置片段
async rewrites() { return { beforeFiles: [ { source: '/football/livescore', destination: '/football/livescore/mobile', has: [ { type: 'header', key: 'x-rewrite', value: '(?<rewrite>yes|true)', }, ], }, { source: '/football/livescore/:league', destination: '/football/livescore/mobile/:league', has: [ { type: 'header', key: 'x-rewrite', value: '(?<rewrite>yes|true)', }, ], }, ], }; },
问题根因
写法存在两个核心逻辑错误,导致重写规则不触发:
- 匹配对象错误:
rewrites配置里has规则匹配的是客户端发起的入站请求头,不是服务端返回给浏览器的响应头。你在middleware中给NextResponse设置的header只会附加到最终响应上,rewrites阶段根本读取不到这个字段。你在浏览器调试工具里能看到x-rewrite响应头,恰恰说明这个头是在响应返回前最后阶段才加上的,早就过了rewrite规则的匹配窗口。 - 执行顺序错误:Next.js的请求处理顺序是「
next.config.js中rewrites规则匹配」→「middleware执行」→「页面/路由渲染」。你在rewrites流程跑完之后才在middleware里设置header,规则自然匹配不到对应值。
解决方案
不要依赖在config中写header匹配规则做UA判断,直接在middleware里完成路径重写即可,逻辑更直接也不会有执行顺序问题。
修改后的pages/_middleware.ts代码:
import { NextRequest, NextResponse } from 'next/server'; const isMobile = (userAgent: string) => /iPhone|iPad|iPod|Android/i.test(userAgent); export function middleware(req: NextRequest) { const userAgent = req.headers.get('user-agent'); const { pathname } = req.nextUrl; // 已经是移动端路径直接放行,避免无限重写 if (pathname.startsWith('/football/livescore/mobile')) { return NextResponse.next(); } if (userAgent && isMobile(userAgent)) { // 移动端访问直接重写到移动端路径 const url = req.nextUrl.clone(); if (pathname === '/football/livescore') { url.pathname = '/football/livescore/mobile'; } else if (pathname.startsWith('/football/livescore/')) { const league = pathname.replace('/football/livescore/', ''); url.pathname = `/football/livescore/mobile/${league}`; } return NextResponse.rewrite(url); } return NextResponse.next(); }
修改完成后,直接删除next.config.js里之前写的两条带header匹配的rewrite规则即可。
注意:如果使用Next.js 12.2以上版本,middleware的文件位置和规范有调整,需要把middleware文件移动到项目根目录(和pages、app目录同级),文件名改为
middleware.ts即可。
内容的提问来源于stack exchange,提问作者Andrii Radkevych
相关产品推荐
相关产品推荐

