跳到内容

API 路由

示例

须知:如果您正在使用 App Router,则可以使用服务器组件路由处理器来代替 API 路由。

API 路由提供了一种使用 Next.js 构建公共 API 的解决方案。

pages/api 文件夹内的任何文件都会映射到 /api/*,并将被视为 API 端点而不是 page。它们是仅服务器端的捆绑包,不会增加客户端捆绑包的大小。

例如,以下 API 路由返回状态码为 200 的 JSON 响应

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
type ResponseData = {
  message: string
}
 
export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

须知:

参数

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  // ...
}

HTTP 方法

要在 API 路由中处理不同的 HTTP 方法,您可以在请求处理程序中使用 req.method,如下所示

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    // Process a POST request
  } else {
    // Handle any other HTTP method
  }
}

请求助手

API 路由提供内置的请求助手,用于解析传入的请求 (req)

  • req.cookies - 包含请求发送的 cookie 的对象。默认为 {}
  • req.query - 包含查询字符串的对象。默认为 {}
  • req.body - 包含按 content-type 解析的正文的对象,如果未发送正文,则为 null

自定义配置

每个 API 路由都可以导出一个 config 对象来更改默认配置,默认配置如下

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
  // Specifies the maximum allowed duration for this function to execute (in seconds)
  maxDuration: 5,
}

bodyParser 默认启用。如果您想将正文作为 Stream 或使用 raw-body 使用,您可以将其设置为 false

禁用自动 bodyParsing 的一个用例是允许您验证 webhook 请求的原始正文,例如来自 GitHub

export const config = {
  api: {
    bodyParser: false,
  },
}

bodyParser.sizeLimit 是解析后的正文允许的最大大小,以 bytes 支持的任何格式表示,如下所示

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '500kb',
    },
  },
}

externalResolver 是一个显式标志,用于告知服务器此路由正在由外部解析器(如 *express* 或 *connect*)处理。启用此选项会禁用未解析请求的警告。

export const config = {
  api: {
    externalResolver: true,
  },
}

responseLimit 默认启用,当 API 路由的响应正文超过 4MB 时发出警告。

如果您不在无服务器环境中使用 Next.js,并且了解不使用 CDN 或专用媒体主机的性能影响,则可以将此限制设置为 false

export const config = {
  api: {
    responseLimit: false,
  },
}

responseLimit 也可以接受字节数或 bytes 支持的任何字符串格式,例如 1000'500kb''3mb'。此值将是显示警告之前的最大响应大小。默认为 4MB。(见上文)

export const config = {
  api: {
    responseLimit: '8mb',
  },
}

响应助手

服务器响应对象(通常缩写为 res)包含一组类似 Express.js 的助手方法,以改善开发者体验并提高创建新 API 端点的速度。

包含的助手是

  • res.status(code) - 用于设置状态码的函数。code 必须是有效的 HTTP 状态码
  • res.json(body) - 发送 JSON 响应。body 必须是可序列化的对象
  • res.send(body) - 发送 HTTP 响应。body 可以是 stringobjectBuffer
  • res.redirect([status,] path) - 重定向到指定的路径或 URL。status 必须是有效的 HTTP 状态码。如果未指定,则 status 默认为 “307” “临时重定向”。
  • res.revalidate(urlPath) - 使用 getStaticProps 按需重新验证页面urlPath 必须是 string

设置响应的状态码

当向客户端发送响应时,您可以设置响应的状态码。

以下示例将响应的状态码设置为 200 (OK),并返回一个 message 属性,其值为 Hello from Next.js! 作为 JSON 响应

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
type ResponseData = {
  message: string
}
 
export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

发送 JSON 响应

当向客户端发送响应时,您可以发送 JSON 响应,这必须是可序列化的对象。在实际应用程序中,您可能希望根据请求端点的结果让客户端知道请求的状态。

以下示例发送状态码为 200 (OK) 的 JSON 响应以及异步操作的结果。它包含在 try catch 块中,以处理可能发生的任何错误,并将捕获到的适当状态码和错误消息发送回客户端

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const result = await someAsyncOperation()
    res.status(200).json({ result })
  } catch (err) {
    res.status(500).json({ error: 'failed to load data' })
  }
}

发送 HTTP 响应

发送 HTTP 响应的方式与发送 JSON 响应的方式相同。唯一的区别是响应正文可以是 stringobjectBuffer

以下示例发送状态码为 200 (OK) 的 HTTP 响应以及异步操作的结果。

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const result = await someAsyncOperation()
    res.status(200).send({ result })
  } catch (err) {
    res.status(500).send({ error: 'failed to fetch data' })
  }
}

重定向到指定的路径或 URL

以表单为例,您可能希望在客户端提交表单后将其重定向到指定的路径或 URL。

以下示例在表单成功提交后将客户端重定向到 / 路径

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const { name, message } = req.body
 
  try {
    await handleFormInputAsync({ name, message })
    res.redirect(307, '/')
  } catch (err) {
    res.status(500).send({ error: 'Failed to fetch data' })
  }
}

添加 TypeScript 类型

您可以通过从 next 导入 NextApiRequestNextApiResponse 类型来使您的 API 路由更具类型安全性,此外,您还可以键入您的响应数据

import type { NextApiRequest, NextApiResponse } from 'next'
 
type ResponseData = {
  message: string
}
 
export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.status(200).json({ message: 'Hello from Next.js!' })
}

须知NextApiRequest 的正文是 any,因为客户端可能包含任何有效负载。您应该在使用正文之前在运行时验证正文的类型/形状。

动态 API 路由

API 路由支持动态路由,并遵循用于 pages/ 的相同文件命名规则。

pages/api/post/[pid].ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { pid } = req.query
  res.end(`Post: ${pid}`)
}

现在,对 /api/post/abc 的请求将以文本响应:Post: abc

捕捉所有 API 路由

可以通过在括号内添加三个点 (...) 来扩展 API 路由以捕捉所有路径。例如

  • pages/api/post/[...slug].js 匹配 /api/post/a,但也匹配 /api/post/a/b/api/post/a/b/c 等。

须知:您可以使用 slug 以外的名称,例如:[...param]

匹配的参数将作为查询参数(示例中为 slug)发送到页面,并且它始终是一个数组,因此,路径 /api/post/a 将具有以下 query 对象

{ "slug": ["a"] }

/api/post/a/b 和任何其他匹配路径的情况下,新参数将添加到数组中,如下所示

{ "slug": ["a", "b"] }

例如

pages/api/post/[...slug].ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { slug } = req.query
  res.end(`Post: ${slug.join(', ')}`)
}

现在,对 /api/post/a/b/c 的请求将以文本响应:Post: a, b, c

可选的捕捉所有 API 路由

通过将参数包含在双括号 ([[...slug]]) 中,可以将捕捉所有路由设置为可选。

例如,pages/api/post/[[...slug]].js 将匹配 /api/post/api/post/a/api/post/a/b 等。

捕捉所有路由和可选捕捉所有路由之间的主要区别在于,对于可选路由,也匹配没有参数的路由(在上面的示例中为 /api/post)。

query 对象如下

{ } // GET `/api/post` (empty object)
{ "slug": ["a"] } // `GET /api/post/a` (single-element array)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (multi-element array)

注意事项

  • 预定义的 API 路由优先于动态 API 路由,而动态 API 路由优先于捕捉所有 API 路由。看看以下示例
    • pages/api/post/create.js - 将匹配 /api/post/create
    • pages/api/post/[pid].js - 将匹配 /api/post/1/api/post/abc 等。但不匹配 /api/post/create
    • pages/api/post/[...slug].js - 将匹配 /api/post/1/2/api/post/a/b/c 等。但不匹配 /api/post/create/api/post/abc

Edge API 路由

如果您想将 API 路由与 Edge Runtime 一起使用,我们建议逐步采用 App Router 并使用路由处理器来代替。

路由处理器的函数签名是同构的,这意味着您可以对 Edge 和 Node.js 运行时使用相同的函数。