添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

中间件

中间件允许你在请求完成之前运行代码。 然后,根据传入的请求,你可以通过重写、重定向、修改请求或响应标头或直接响应来修改响应。

Middleware allows you to run code before a request is completed. Then, based on the incoming request, you can modify the response by rewriting, redirecting, modifying the request or response headers, or responding directly.

中间件在缓存内容和路由匹配之前运行。 详细信息请参见 匹配路径

Middleware runs before cached content and routes are matched. See Matching Paths for more details.

使用项目根目录中的文件 middleware.ts (或 .js )来定义中间件。 例如,与 pages app 处于同一级别,或者在 src 内部(如果适用)。

Use the file middleware.ts (or .js ) in the root of your project to define Middleware. For example, at the same level as pages or app , or inside src if applicable.

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
return NextResponse.redirect(new URL('/home', request.url))
}

// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*',
}
import { NextResponse } from 'next/server'

// This function can be marked `async` if using `await` inside
export function middleware(request) {
return NextResponse.redirect(new URL('/home', request.url))
}

// See "Matching Paths" below to learn more
export const config = {
matcher: '/about/:path*',
}

匹配路径

将为 项目中的每条路线 调用中间件。 以下是执行顺序:

Middleware will be invoked for every route in your project . The following is the execution order:

  • headers next.config.js
  • redirects next.config.js
  • 中间件( rewrites redirects 等)
  • beforeFiles ( rewrites ) 从 next.config.js
  • 文件系统路由( public/ _next/static/ pages/ app/ 等)
  • afterFiles ( rewrites ) 从 next.config.js
  • 动态路线 ( /blog/[slug] )
  • fallback ( rewrites ) 从 next.config.js
  • 有两种方法可以定义中间件将在哪些路径上运行:

    There are two ways to define which paths Middleware will run on:

  • 自定义匹配器配置
  • 匹配器

    matcher 允许你过滤中间件以在特定路径上运行。

    matcher allows you to filter Middleware to run on specific paths.

    export const config = {
    matcher: '/about/:path*',
    }

    你可以使用数组语法匹配单个路径或多个路径:

    You can match a single path or multiple paths with an array syntax:

    export const config = {
    matcher: ['/about/:path*', '/dashboard/:path*'],
    }

    matcher 配置允许完整的正则表达式,因此支持负向查找或字符匹配等匹配。 可以在此处查看用于匹配除特定路径之外的所有路径的负前瞻示例:

    The matcher config allows full regex so matching like negative lookaheads or character matching is supported. An example of a negative lookahead to match all except specific paths can be seen here:

    export const config = {
    matcher: [
    /*
    * Match all request paths except for the ones starting with:
    * - api (API routes)
    * - _next/static (static files)
    * - _next/image (image optimization files)
    * - favicon.ico (favicon file)
    */
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
    ],
    }

    很高兴知道 matcher 值需要是常量,以便可以在构建时对其进行静态分析。 诸如变量之类的动态值将被忽略。

    配置的匹配器:

    Configured matchers:

  • 必须以 / 开头
  • 可以包含命名参数: /about/:path 匹配 /about/a /about/b ,但不匹配 /about/a/c
  • 可以对命名参数进行修饰符(以 : 开头): /about/:path* /about/a/b/c 匹配,因为 * 为零或更大。 ? 为零或一, + 为一或多个
  • 可以使用括号括起来的正则表达式: /about/(.*) /about/:path* 相同
  • 阅读有关 path-to-regexp 文档的更多详细信息。

    Read more details on path-to-regexp documentation.

    很高兴知道 : 为了向后兼容,Next.js 始终将 /public 视为 /public/index 。 因此, /public/:path 的匹配器将匹配。

    条件语句

    import { NextResponse } from 'next/server'
    import type { NextRequest } from 'next/server'

    export function middleware(request: NextRequest) {
    if (request.nextUrl.pathname.startsWith('/about')) {
    return NextResponse.rewrite(new URL('/about-2', request.url))
    }

    if (request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.rewrite(new URL('/dashboard/user', request.url))
    }
    }
    import { NextResponse } from 'next/server'

    export function middleware(request) {
    if (request.nextUrl.pathname.startsWith('/about')) {
    return NextResponse.rewrite(new URL('/about-2', request.url))
    }

    if (request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.rewrite(new URL('/dashboard/user', request.url))
    }
    }

    NextResponse

    NextResponse API 允许你:

    The NextResponse API allows you to:

  • redirect 传入请求到不同的 URL
  • rewrite 通过显示给定 URL 进行响应
  • 设置 API 路由、 getServerSideProps rewrite 目标的请求标头
  • 设置响应 cookie
  • 设置响应头
  • 要从中间件生成响应,你可以:

    To produce a response from Middleware, you can:

  • rewrite 到产生响应的路由( 页面 路由处理程序
  • 直接返回 NextResponse 。 见 产生响应
  • 使用 Cookie

    Cookie 是常规标头。 在 Request 上,它们存储在 Cookie 标头中。 在 Response 上,它们位于 Set-Cookie 标头中。 Next.js 通过 NextRequest NextResponse 上的 cookies 扩展提供了一种便捷的方式来访问和操作这些 cookie。

    Cookies are regular headers. On a Request , they are stored in the Cookie header. On a Response they are in the Set-Cookie header. Next.js provides a convenient way to access and manipulate these cookies through the cookies extension on NextRequest and NextResponse .

  • 对于传入的请求, cookies 带有以下方法: get getAll set delete cookie。 你可以检查 has 的 cookie 是否存在,或者删除 clear 的所有 cookie。
  • 对于传出响应, cookies 有以下方法 get getAll set delete
  • import { NextResponse } from 'next/server'
    import type { NextRequest } from 'next/server'

    export function middleware(request: NextRequest) {
    // Assume a "Cookie:nextjs=fast" header to be present on the incoming request
    // Getting cookies from the request using the `RequestCookies` API
    let cookie = request.cookies.get('nextjs')
    console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
    const allCookies = request.cookies.getAll()
    console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]

    request.cookies.has('nextjs') // => true
    request.cookies.delete('nextjs')
    request.cookies.has('nextjs') // => false

    // Setting cookies on the response using the `ResponseCookies` API
    const response = NextResponse.next()
    response.cookies.set('vercel', 'fast')
    response.cookies.set({
    name: 'vercel',
    value: 'fast',
    path: '/',
    })
    cookie = response.cookies.get('vercel')
    console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
    // The outgoing response will have a `Set-Cookie:vercel=fast;path=/test` header.

    return response
    }
    import { NextResponse } from 'next/server'

    export function middleware(request) {
    // Assume a "Cookie:nextjs=fast" header to be present on the incoming request
    // Getting cookies from the request using the `RequestCookies` API
    let cookie = request.cookies.get('nextjs')
    console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
    const allCookies = request.cookies.getAll()
    console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]

    request.cookies.has('nextjs') // => true
    request.cookies.delete('nextjs')
    request.cookies.has('nextjs') // => false

    // Setting cookies on the response using the `ResponseCookies` API
    const response = NextResponse.next()
    response.cookies.set('vercel', 'fast')
    response.cookies.set({
    name: 'vercel',
    value: 'fast',
    path: '/',
    })
    cookie = response.cookies.get('vercel')
    console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
    // The outgoing response will have a `Set-Cookie:vercel=fast;path=/test` header.

    return response
    }

    设置标题

    你可以使用 NextResponse API 设置请求和响应标头(自 Next.js v13.0.0 起可以设置请求标头)。

    You can set request and response headers using the NextResponse API (setting request headers is available since Next.js v13.0.0).

    import { NextResponse } from 'next/server'
    import type { NextRequest } from 'next/server'

    export function middleware(request: NextRequest) {
    // Clone the request headers and set a new header `x-hello-from-middleware1`
    const requestHeaders = new Headers(request.headers)
    requestHeaders.set('x-hello-from-middleware1', 'hello')

    // You can also set request headers in NextResponse.rewrite
    const response = NextResponse.next({
    request: {
    // New request headers
    headers: requestHeaders,
    },
    })

    // Set a new response header `x-hello-from-middleware2`
    response.headers.set('x-hello-from-middleware2', 'hello')
    return response
    }
    import { NextResponse } from 'next/server'

    export function middleware(request) {
    // Clone the request headers and set a new header `x-hello-from-middleware1`
    const requestHeaders = new Headers(request.headers)
    requestHeaders.set('x-hello-from-middleware1', 'hello')

    // You can also set request headers in NextResponse.rewrite
    const response = NextResponse.next({
    request: {
    // New request headers
    headers: requestHeaders,
    },
    })

    // Set a new response header `x-hello-from-middleware2`
    response.headers.set('x-hello-from-middleware2', 'hello')
    return response
    }

    很高兴知道 : 避免设置大标头,因为它可能会导致 431 请求标头字段太大 错误,具体取决于你的后端 Web 服务器配置。

    产生响应

    你可以通过返回 Response NextResponse 实例直接从中间件进行响应。 (从 Next.js v13.1.0 年开始可用)

    You can respond from Middleware directly by returning a Response or NextResponse instance. (This is available since Next.js v13.1.0 )

    import { NextRequest } from 'next/server'
    import { isAuthenticated } from '@lib/auth'

    // Limit the middleware to paths starting with `/api/`
    export const config = {
    matcher: '/api/:function*',
    }

    export function middleware(request: NextRequest) {
    // Call our authentication function to check the request
    if (!isAuthenticated(request)) {
    // Respond with JSON indicating an error message
    return Response.json(
    { success: false, message: 'authentication failed' },
    { status: 401 }
    )
    }
    }
    import { isAuthenticated } from '@lib/auth'

    // Limit the middleware to paths starting with `/api/`
    export const config = {
    matcher: '/api/:function*',
    }

    export function middleware(request) {
    // Call our authentication function to check the request
    if (!isAuthenticated(request)) {
    // Respond with JSON indicating an error message
    return Response.json(
    { success: false, message: 'authentication failed' },
    { status: 401 }
    )
    }
    }

    高级中间件标志

    在 Next.js 的 v13.1 中,为中间件引入了两个附加标志 skipMiddlewareUrlNormalize skipTrailingSlashRedirect 来处理高级用例。

    In v13.1 of Next.js two additional flags were introduced for middleware, skipMiddlewareUrlNormalize and skipTrailingSlashRedirect to handle advanced use cases.

    skipTrailingSlashRedirect 允许禁用 Next.js 默认重定向以添加或删除尾部斜杠,从而允许中间件内部进行自定义处理,这可以允许维护某些路径的尾部斜杠,但不允许维护其他路径的尾部斜杠,从而允许更轻松的增量迁移。

    skipTrailingSlashRedirect allows disabling Next.js default redirects for adding or removing trailing slashes allowing custom handling inside middleware which can allow maintaining the trailing slash for some paths but not others allowing easier incremental migrations.

    module.exports = {
    skipTrailingSlashRedirect: true,
    }
    const legacyPrefixes = ['/docs', '/blog']

    export default async function middleware(req) {
    const { pathname } = req.nextUrl

    if (legacyPrefixes.some((prefix) => pathname.startsWith(prefix))) {
    return NextResponse.next()
    }

    // apply trailing slash handling
    if (
    !pathname.endsWith('/') &&
    !pathname.match(/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
    ) {
    req.nextUrl.pathname += '/'
    return NextResponse.redirect(req.nextUrl)
    }
    }

    skipMiddlewareUrlNormalize 允许禁用 Next.js 的 URL 规范化功能,以使直接访问和客户端转换的处理相同。 在某些高级情况下,你需要使用解锁的原始 URL 进行完全控制。

    skipMiddlewareUrlNormalize allows disabling the URL normalizing Next.js does to make handling direct visits and client-transitions the same. There are some advanced cases where you need full control using the original URL which this unlocks.