跳到內容

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 是一個明確的標誌,告知伺服器此路由正由外部解析器(如 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',
  },
}

回應輔助程式

伺服器回應物件(通常縮寫為 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),並傳回具有值為 Hello from Next.js!message 屬性作為 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 路由

如果您想要搭配 Edge Runtime 使用 API 路由,我們建議逐步採用 App Router 並改用路由處理器

路由處理器函數簽名是同構的,這表示您可以對 Edge 和 Node.js 執行階段使用相同的函數。