Proxy 代理

2026年9月6日

从 Next.js 16 起,中间件文件和导出函数改叫 Proxy,能力没变,名字更贴近「请求到达页面前先拦一层」。升级可以用官方 codemod:

npx @next/codemod@canary middleware-to-proxy .
bash

它会把 middleware.ts / middleware() 改成 proxy.ts / proxy()


基本写法

在项目源码根(有 src/ 就放 src/proxy.ts)导出 proxy

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

export async function proxy(request: NextRequest) {
  console.log(request.nextUrl.pathname);
  return NextResponse.next();
}
ts

不配 matcher 时,静态资源、HMR、页面、接口全都会进来,开发时日志会刷屏。先收窄范围。


matcher

export const config = {
  matcher: "/api/:path*",
};
ts

多个路径、或排除 _next

export const config = {
  matcher: [
    "/api/:path*",
    "/home/:path*",
    "/((?!_next/static|_next/image|.*\\.png$).*)",
  ],
};
ts

鉴权跳转

上一篇用 cookie 记登录。保护 /home 可以不再单独打检查接口:

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

export async function proxy(request: NextRequest) {
  const token = request.cookies.get("token");
  const { pathname } = request.nextUrl;

  if (pathname.startsWith("/home") && !token) {
    return NextResponse.redirect(new URL("/", request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/home/:path*"],
};
ts

没 cookie 就 307 回首页;有就放行。


更细的匹配

matcher 可以写成对象:source + has(必须带上)+ missing(必须没有)。type 只能是 headerquerycookie

import type { ProxyConfig } from "next/server";

export const config: ProxyConfig = {
  matcher: [
    {
      source: "/home/:path*",
      has: [
        { type: "header", key: "authorization" },
        { type: "query", key: "userId" },
      ],
      missing: [{ type: "cookie", key: "guest" }],
    },
  ],
};
ts

只有条件都满足时,proxy 才会跑。适合「带特定头才走这套逻辑」。


给接口加 CORS

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

const cors = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
};

export async function proxy(request: NextRequest) {
  if (request.method === "OPTIONS") {
    return new NextResponse(null, { status: 204, headers: cors });
  }

  const res = NextResponse.next();
  for (const [k, v] of Object.entries(cors)) {
    res.headers.set(k, v);
  }
  return res;
}

export const config = {
  matcher: "/api/:path*",
};
ts

生产环境把 * 换成明确的前端源。Proxy 还可以做简单限流、改请求头、把 /api 转到别的语言服务——先把 matcher 收紧,再往函数里加逻辑。

下一篇看样式:Tailwind、CSS Modules、Sass、全局 CSS。


参考文档