NextRequest 与 NextResponse

next/server 提供了专用于中间件边缘 API 路由的服务端辅助工具。

NextRequest

NextRequest 对象是对原生 Request 接口的扩展,新增了以下方法和属性:

  • cookies - 一个包含请求中 Cookie 的 RequestCookies 实例。可读取/修改请求的 Cookie 头。另请参阅在中间件中使用 Cookie

    • get - 接收 Cookie 名称,返回包含 namevalue 的对象。若未找到对应名称的 Cookie 则返回 undefined。若存在多个匹配项,仅返回第一个匹配项。
    • getAll - 类似 get 方法,但返回所有匹配名称的 Cookie 列表。若未指定名称,则返回所有可用 Cookie。
    • set - 接收符合 W3C CookieStore API 规范中 CookieListItem 属性的对象。
    • delete - 接收 Cookie 名称或名称列表,删除匹配的 Cookie。返回 true 表示删除成功,false 表示未删除。
    • has - 接收 Cookie 名称,返回布尔值表示该 Cookie 是否存在。
    • clear - 无参数方法,将直接移除 Cookie 头。
  • nextUrl: 包含扩展的解析后 URL 对象,可访问 Next.js 特有属性如 pathnamebasePathtrailingSlashi18n。包含以下属性:

    • basePath (string)
    • buildId (string || undefined)
    • defaultLocale (string || undefined)
    • domainLocale
      • defaultLocale: (string)
      • domain: (string)
      • http: (boolean || undefined)
      • locales: (string[] || undefined)
    • locale (string || undefined)
    • url (URL)
  • ip: (string || undefined) - 包含请求的 IP 地址。该信息由托管平台提供。

  • geo - 包含请求的地理位置信息。该信息由托管平台提供。包含以下属性:

    • city (string || undefined)
    • country (string || undefined)
    • region (string || undefined)
    • latitude (string || undefined)
    • longitude (string || undefined)

您可以将 NextRequest 对象作为原生 Request 接口的直接替代,从而获得更多控制请求的能力。

可从 next/server 导入 NextRequest

import type { NextRequest } from 'next/server'

NextFetchEvent

NextFetchEvent 对象扩展了原生 FetchEvent 对象,并包含 waitUntil() 方法。

waitUntil() 方法可用于延长函数执行时间,以便完成其他后台任务。

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

export function middleware(req: NextRequest, event: NextFetchEvent) {
  event.waitUntil(
    fetch('https://my-analytics-platform.com', {
      method: 'POST',
      body: JSON.stringify({ pathname: req.nextUrl.pathname }),
    })
  )

  return NextResponse.next()
}

可从 next/server 导入 NextFetchEvent

import type { NextFetchEvent } from 'next/server'

NextResponse

NextResponse 类扩展了原生 Response 接口,具有以下特性:

公共方法

公共方法可通过 NextResponse 类实例调用。根据使用场景,您可以创建实例并赋值给变量,然后访问以下公共方法:

  • cookies - 一个包含响应中 Cookie 的 ResponseCookies 实例。可读取/修改响应的 Set-Cookie 头。另请参阅在中间件中使用 Cookie
    • get - 接收 Cookie 名称,返回包含 namevalue 的对象。若未找到对应名称的 Cookie 则返回 undefined。若存在多个匹配项,仅返回第一个匹配项。
    • getAll - 类似 get 方法,但返回所有匹配名称的 Cookie 列表。若未指定名称,则返回所有可用 Cookie。
    • set - 接收符合 W3C CookieStore API 规范中 CookieListItem 属性的对象。
    • delete - 接收 Cookie 名称或名称列表,删除匹配的 Cookie。返回 true 表示删除成功,false 表示未删除。

静态方法

以下静态方法可直接通过 NextResponse 类调用:

  • redirect() - 返回设置了重定向的 NextResponse
  • rewrite() - 返回设置了重写的 NextResponse
  • next() - 返回将继续中间件链的 NextResponse

使用上述方法时,必须返回方法返回的 NextResponse 对象。可从 next/server 导入 NextResponse

import { NextResponse } from 'next/server'

userAgent

userAgent 辅助工具允许您与请求中的用户代理对象交互。它抽象自原生 Request 对象,是一项可选功能。具有以下属性:

  • isBot: (boolean) 请求是否来自已知爬虫
  • browser
    • name: (string || undefined) 浏览器名称
    • version: (string || undefined) 动态确定的浏览器版本
  • device
    • model: (string || undefined) 动态确定的设备型号
    • type: (string || undefined) 浏览器类型,可能值为:consolemobiletabletsmarttvwearableembeddedundefined
    • vendor: (string || undefined) 动态确定的设备厂商
  • engine
    • name: (string || undefined) 浏览器引擎名称,可能值为:AmayaBlinkEdgeHTMLFlowGeckoGoannaiCabKHTMLLinksLynxNetFrontNetSurfPrestoTasmanTridentw3mWebKitundefined
    • version: (string || undefined) 动态确定的浏览器引擎版本或 undefined
  • os
    • name: (string || undefined) 操作系统名称,可能为 undefined
    • version: (string || undefined) 动态确定的操作系统版本或 undefined
  • cpu
    • architecture: (string || undefined) CPU 架构,可能值为:68kamd64armarm64armhfavria32ia64irixirix64mipsmips64pa-riscppcsparcsparc64undefined

可从 next/server 导入 userAgent

import { userAgent } from 'next/server'
import { NextRequest, NextResponse, userAgent } from 'next/server'

export function middleware(request: NextRequest) {
  const url = request.nextUrl
  const { device } = userAgent(request)
  const viewport = device.type === 'mobile' ? 'mobile' : 'desktop'
  url.searchParams.set('viewport', viewport)
  return NextResponse.rewrite(url)
}

常见问题

为什么 redirect 使用 307 和 308?

使用 redirect() 时,您可能会注意到临时重定向使用 307 状态码,永久重定向使用 308。传统上临时重定向使用 302,永久重定向使用 301,但许多浏览器在使用 302 时会将重定向请求方法从 POST 改为 GET,无论原始请求方法是什么。

以从 /users 重定向到 /people 为例,如果您向 /users 发送 POST 请求创建新用户,并遵循 302 临时重定向,请求方法将从 POST 变为 GET。这不符合逻辑,因为创建新用户应该向 /people 发送 POST 请求而非 GET

引入 307 状态码意味着请求方法将保留为 POST

  • 302 - 临时重定向,会将请求方法从 POST 改为 GET
  • 307 - 临时重定向,会保留请求方法为 POST

redirect() 方法默认使用 307 而非 302 临时重定向,意味着您的请求将始终保留为 POST 方法。

如果您希望 POST 请求返回 GET 响应,请使用 303

了解更多关于 HTTP 重定向的信息。

如何访问环境变量?

可通过 process.env 在边缘中间件中访问环境变量。这些变量在 next build 时被评估:

有效用法无效用法
console.log(process.env.MY_ENV_VARIABLE)const getEnv = name => process.env[name]
const { MY_ENV_VARIABLE } = process.env
const { "MY-ENV-VARIABLE": MY_ENV_VARIABLE } = process.env

On this page