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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:51:17