API 路由

範例

須知事項:若您使用 App Router,可以改用 伺服器元件 (Server Components)路由處理器 (Route Handlers) 來替代 API 路由。

API 路由提供了一個在 Next.js 中建立 公開 API 的解決方案。

任何位於 pages/api 資料夾內的檔案都會被映射到 /api/* 路徑,並被視為 API 端點而非頁面。這些檔案僅在伺服器端打包,不會增加客戶端的打包體積。

例如,以下 API 路由會回傳狀態碼為 200 的 JSON 回應:

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,如下所示:

import type { NextApiRequest, NextApiResponse } from 'next'

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    // 處理 POST 請求
  } else {
    // 處理其他 HTTP 方法
  }
}

請求輔助工具

API 路由提供了內建的請求輔助工具,用於解析傳入的請求 (req):

  • req.cookies - 包含請求傳送的 cookies 的物件。預設為 {}
  • req.query - 包含 查詢字串 (query string) 的物件。預設為 {}
  • req.body - 包含由 content-type 解析的內容主體,若未傳送主體則為 null

自訂設定

每個 API 路由都可以匯出一個 config 物件來修改預設設定,預設設定如下:

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
  // 指定此函式執行的最大允許時間(以秒為單位)
  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 是一個明確的標記,告訴伺服器此路由由外部解析器(如 expressconnect)處理。啟用此選項會停用未解析請求的警告。

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',
  },
}

回應輔助工具

伺服器回應物件 (Server Response object)(通常簡稱為 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) - 按需重新驗證頁面 使用 getStaticPropsurlPath 必須是 string

設定回應的狀態碼

在傳送回應給客戶端時,您可以設定回應的狀態碼。

以下範例將回應的狀態碼設為 200OK),並以 JSON 回應傳送 message 屬性,其值為 Hello from Next.js!

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 回應,這必須是一個 可序列化物件。 在實際應用中,您可能會希望根據請求端點的結果讓客戶端知道請求的狀態。

以下範例傳送狀態碼為 200OK)的 JSON 回應,以及非同步操作的結果。它包含在 try catch 區塊中,以處理可能發生的錯誤,並捕捉適當的狀態碼和錯誤訊息傳回給客戶端:

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

以下範例傳送狀態碼為 200OK)的 HTTP 回應,以及非同步操作的結果。

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。

以下範例在表單成功提交後將客戶端重新導向至 / 路徑:

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/ 相同的檔案命名規則。

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"] }

例如:

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` (空物件)
{ "slug": ["a"] } // `GET /api/post/a` (單元素陣列)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (多元素陣列)

注意事項

  • 預定義的 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

串流回應

雖然 Pages Router 支援透過 API 路由進行串流回應,但如果您使用的是 Next.js 14+,我們建議逐步採用 App Router 並使用 路由處理器 (Route Handlers)

以下是如何使用 writeHead 從 API 路由串流回應的範例:

pages/api/hello.js
import { NextApiRequest, NextApiResponse } from 'next'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': "no-store",
  })
  let i = 0
  while (i < 10) {
    res.write(`data: ${i}\n\n`)
    i++
    await new Promise((resolve) => setTimeout(resolve, 1000))
  }
  res.end()
}

On this page