nextjs-16-proxy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Next.js 16 Proxy Convention

Next.js 16 代理约定

Next.js 16 renamed
middleware
to
proxy
to better reflect its network boundary purpose.
Next.js 16 将
middleware
重命名为
proxy
,以更准确地体现其网络边界的作用。

Key Changes from Middleware

与旧版中间件的主要变化

Old (Next.js 15)New (Next.js 16+)
middleware.ts
proxy.ts
export function middleware()
export function proxy()
Same locationSame location
Next.js 15(旧版)Next.js 16+(新版)
middleware.ts
proxy.ts
export function middleware()
export function proxy()
位置不变位置不变

File Location

文件位置

Place
proxy.ts
at the same level as
app
or
pages
:
src/
├── proxy.ts      ← Correct location
├── app/
│   └── ...
NOT inside
app/
:
src/
├── app/
│   ├── proxy.ts  ← Wrong location
│   └── ...
proxy.ts
放置在与
app
pages
同级的目录下:
src/
├── proxy.ts      ← 正确位置
├── app/
│   └── ...
不要放在
app/
目录内:
src/
├── app/
│   ├── proxy.ts  ← 错误位置
│   └── ...

Basic Template

基础模板

typescript
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function proxy(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Example: rewrite /uploads/* to /api/uploads/*
  if (pathname.startsWith("/uploads/")) {
    const newUrl = request.nextUrl.clone();
    newUrl.pathname = pathname.replace("/uploads/", "/api/uploads/");
    return NextResponse.rewrite(newUrl);
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/uploads/:path*"],
};
typescript
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function proxy(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // 示例:将/uploads/*重写为/api/uploads/*
  if (pathname.startsWith("/uploads/")) {
    const newUrl = request.nextUrl.clone();
    newUrl.pathname = pathname.replace("/uploads/", "/api/uploads/");
    return NextResponse.rewrite(newUrl);
  }

  return NextResponse.next();
}

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

Common Issue: Dynamic Routes Catching Paths

常见问题:动态路由捕获路径

When you have a dynamic route like
[teamSlug]
at the root, it can catch paths before rewrites in
next.config.ts
are applied.
Problem:
  • Request:
    /uploads/image.png
  • Dynamic route
    [teamSlug]
    catches it as
    teamSlug = "uploads"
  • Results in 404
Solution: Use
proxy.ts
instead of
next.config.ts
rewrites. Proxy runs before routing.
当你在根目录有一个类似
[teamSlug]
的动态路由时,它可能会在
next.config.ts
中的重写规则生效前捕获路径。
问题:
  • 请求:
    /uploads/image.png
  • 动态路由
    [teamSlug]
    会将其捕获为
    teamSlug = "uploads"
  • 导致404错误
解决方案: 使用
proxy.ts
替代
next.config.ts
中的重写规则。Proxy会在路由匹配之前运行。

Migration Command

迁移命令

bash
npx @next/codemod@canary middleware-to-proxy .
This automatically:
  • Renames
    middleware.ts
    proxy.ts
  • Updates function name
    middleware
    proxy
bash
npx @next/codemod@canary middleware-to-proxy .
该命令会自动执行以下操作:
  • middleware.ts
    重命名为
    proxy.ts
  • 将函数名
    middleware
    更新为
    proxy