本指南將涵蓋如何使用 Next.js 建構 API,包括設定專案、理解 App Router 與 Route Handlers、處理多種 HTTP 方法、實作動態路由、建立可重複使用的中介層邏輯,以及決定何時需要建立專用的 API 層。
- 1. 開始使用
- 2. 為何(以及何時)使用 Next.js 建構 API
- 3. 使用 Route Handlers 建立 API
- 4. 使用 Web API
- 5. 動態路由
- 6. 使用 Next.js 作為代理或轉發層
- 7. 建立共用的「中介層」邏輯
- 8. 部署與「SPA 模式」考量
- 9. 何時不需要建立 API 端點
- 10. 整合所有內容
- 結論
- 常見問題
1. 開始使用
1.1 建立 Next.js 應用程式
如果從頭開始,可以使用以下指令建立新的 Next.js 專案:
npx create-next-app@latest --api
注意:
--api
旗標會自動在新專案的app/
資料夾中包含一個範例route.ts
,展示如何建立 API 端點。
1.2 App Router 與 Pages Router
- Pages Router:Next.js 過去使用
pages/api/*
來建立 API。這種方式依賴 Node.js 的 request/response 物件和類似 Express 的 API。 - App Router(預設):Next.js 13 引入的 App Router 完全採用 Web 標準的 Request/Response API。現在可以在
app/
目錄中的任何位置放置route.ts
或route.js
檔案,而不需要使用pages/api/*
。
為何切換? App Router 的「Route Handlers」基於 Web Platform Request/Response APIs,而非 Node.js 特定的 API。這簡化了學習過程,減少摩擦,並幫助你在不同工具之間重用知識。
2. 為何(以及何時)使用 Next.js 建構 API
-
供多種客戶端使用的公開 API
- 你可以建立一個公開 API,供 Next.js 網頁應用、獨立的行動應用或任何第三方服務使用。例如,你可能在 React 網站和 React Native 行動應用中從
/api/users
獲取資料。
- 你可以建立一個公開 API,供 Next.js 網頁應用、獨立的行動應用或任何第三方服務使用。例如,你可能在 React 網站和 React Native 行動應用中從
-
代理至現有後端
- 有時你想隱藏或整合外部的 微服務 至單一端點。Next.js Route Handlers 可以作為代理或中間層,轉發至另一個現有的後端。例如,你可以攔截請求、處理身份驗證、轉換資料,然後將請求轉發至上游 API。
-
Webhooks 與整合
- 如果你接收來自外部的回調或 webhooks(例如來自 Stripe、GitHub、Twilio),可以使用 Route Handlers 處理它們。
-
自訂身份驗證
- 如果需要會話、令牌或其他身份驗證邏輯,可以在 Next.js API 層中儲存 cookies、讀取標頭並回傳適當的資料。
注意: 如果僅需要為自己的 Next.js 應用進行伺服器端資料獲取(且不需要與外部共享這些資料),Server Components 可能足以在渲染時直接獲取資料,無需獨立的 API 層。
3. 使用 Route Handlers 建立 API
3.1 基本檔案設定
在 App Router (app/
) 中,建立一個代表路由的資料夾,並在其中建立 route.ts
檔案。
例如,建立一個位於 /api/users
的端點:
app
└── api
└── users
└── route.ts
3.2 在單一檔案中使用多種 HTTP 方法
與 Pages Router 的 API 路由(僅有一個預設導出)不同,你可以在同一個檔案中導出多個代表不同 HTTP 方法的函式。
export async function GET(request: Request) {
// 例如,從資料庫獲取資料
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
return new Response(JSON.stringify(users), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
}
export async function POST(request: Request) {
// 解析請求主體
const body = await request.json();
const { name } = body;
// 例如,將新使用者插入資料庫
const newUser = { id: Date.now(), name };
return new Response(JSON.stringify(newUser), {
status: 201,
headers: { 'Content-Type': 'application/json' }
});
}
現在,發送 GET 請求至 /api/users
會回傳使用者列表,而發送 POST 請求至相同 URL 則會新增使用者。
4. 使用 Web API
4.1 直接使用 Request 與 Response
預設情況下,你的 Route Handler 方法(GET
、POST
等)會接收一個標準的 Request 物件,並且必須回傳一個標準的 Response 物件。
4.2 查詢參數
import { NextRequest } from 'next/server';
export function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const query = searchParams.get('query'); // 例如 `/api/search?query=hello`
return new Response(
JSON.stringify({ result: `你搜尋了:${query}` }),
{
headers: { 'Content-Type': 'application/json' },
},
);
}
4.3 標頭與 cookies
import { NextRequest } from 'next/server';
import { cookies, headers } from 'next/headers';
export async function GET(request: NextRequest) {
// 1. 使用 'next/headers' 輔助函式
const cookieStore = await cookies();
const token = cookieStore.get('token');
const headersList = await headers();
const referer = headersList.get('referer');
// 2. 使用標準 Web API
const userAgent = request.headers.get('user-agent');
return new Response(JSON.stringify({ token, referer, userAgent }), {
headers: { 'Content-Type': 'application/json' },
});
}
cookies()
和 headers()
函式在需要在 Next.js 的其他伺服器端程式碼中重用共用邏輯時非常有用。你會注意到 Next.js 也提供了 NextRequest
和 NextResponse
,它們擴充了基礎的 Web API。
5. 動態路由
要建立動態路徑(例如 /api/users/:id
),請在資料夾結構中使用 動態區段:
app
└── api
└── users
└── [id]
└── route.ts
此檔案對應於像 /api/users/123
這樣的 URL,其中 123
會被捕捉為參數。
import { NextRequest } from 'next/server';
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> },
) {
const id = (await params).id;
// 例如,查詢資料庫中 ID 為 `id` 的使用者
return new Response(JSON.stringify({ id, name: `使用者 ${id}` }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> },
) {
const id = (await params).id;
// 例如,刪除資料庫中 ID 為 `id` 的使用者
return new Response(null, { status: 204 });
}
此處,params.id
提供了動態區段的值。
6. 使用 Next.js 作為代理或轉發層
一個常見情境是 代理 現有的後端服務。你可以在將請求發送至遠端伺服器或後端之前,進行身份驗證、處理日誌記錄或轉換資料:
import { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
const response = await fetch('https://example.com/api/data', {
// 可選:轉發某些標頭、新增驗證令牌等
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` },
});
// 轉換或轉發回應
const data = await response.json();
const transformed = { ...data, source: '透過-nextjs-代理' };
return new Response(JSON.stringify(transformed), {
headers: { 'Content-Type': 'application/json' },
});
}
現在你的客戶端只需呼叫 /api/external
,Next.js 會處理其餘部分。這有時也被稱為「Backend for Frontend」或 BFF。
7. 建立共用的「中介層」邏輯
如果想在多個 Route Handlers 中套用相同的邏輯(例如身份驗證檢查、日誌記錄),可以建立可重複使用的函式來包裝你的處理器:
import { NextRequest } from 'next/server';
type Handler = (req: NextRequest, context?: any) => Promise<Response>;
export function withAuth(handler: Handler): Handler {
return async (req, context) => {
const token = req.cookies.get('token')?.value;
if (!token) {
return new Response(JSON.stringify({ error: '未經授權' }), {
status: 401,
headers: { 'Content-Type': 'application/json' },
});
}
// 如果已驗證,呼叫原始處理器
return handler(req, context);
};
}
然後在你的 Route Handler 中:
import { NextRequest } from 'next/server';
import { withAuth } from '@/lib/with-auth';
async function secretGET(request: NextRequest) {
return new Response(JSON.stringify({ secret: '這裡有龍' }), {
headers: { 'Content-Type': 'application/json' },
});
}
export const GET = withAuth(secretGET);
8. 部署與「SPA 模式」考量
8.1 標準 Node.js 部署
使用 next start
的標準 Next.js 伺服器部署讓你能使用 Route Handlers、Server Components、Middleware 等功能,同時利用動態的請求時間資訊。
無需額外設定。詳見 部署。
8.2 SPA/靜態匯出
Next.js 也支援將整個網站輸出為 靜態單頁應用程式 (SPA)。
可以透過以下設定啟用:
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
output: 'export',
};
export default nextConfig;
在 靜態匯出模式 下,Next.js 會生成純靜態的 HTML、CSS 和 JS。無法執行伺服器端程式碼(如 API 端點)。如果仍需要 API,必須單獨託管(例如獨立的 Node.js 伺服器)。
注意:
- GET Route Handlers 可以靜態匯出,前提是它們不依賴動態請求資料。它們會成為
out
資料夾中的靜態檔案。- 所有其他伺服器功能(動態請求、重寫 cookies 等)不支援純 SPA 匯出。
8.3 在 Vercel 上部署 API
如果您要將 Next.js 應用程式部署到 Vercel,我們提供了 API 部署指南。這包括其他 Vercel 功能,例如透過 Vercel 防火牆實現的 程式化速率限制。Vercel 還提供 Cron Jobs,這是 API 方法中常見的需求。
9. 何時不需要建立 API 端點
使用 App Router 的 React 伺服器元件 (React Server Components),您可以直接在伺服器上獲取資料,而無需公開端點:
// (伺服器元件)
export default async function UsersPage() {
// 此 fetch 在伺服器端執行(此處不需要客戶端程式碼)
const res = await fetch('https://api.example.com/users');
const data = await res.json();
return (
<main>
<h1>使用者</h1>
<ul>
{data.map((user: any) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</main>
);
}
如果您的資料僅在 Next.js 應用中使用,您可能完全不需要公開 API。
10. 綜合應用
- 建立新的 Next.js 專案:
npx create-next-app@latest --api
。 - 在
app/
目錄中新增路由處理器(例如app/api/users/route.ts
)。 - 在相同檔案中匯出 HTTP 方法(
GET
、POST
、PUT
、DELETE
等)。 - 使用網頁標準 API 與
Request
物件互動並回傳Response
。 - 如果需要其他客戶端使用您的資料,或需要代理後端服務,建立公開 API。
- 從客戶端獲取您的新 API 路由(例如在客戶端元件中使用
fetch('/api/...')
)。 - 或者,如果伺服器元件可以直接獲取資料,完全不需要建立 API。
- 為驗證或其他重複邏輯**新增共享的「中介層」**模式(例如
withAuth()
)。 - 如需伺服器功能,部署到支援 Node.js 的環境;如果只需要靜態 SPA,則匯出靜態檔案。
結論
使用 Next.js 的 App Router 和 路由處理器,您可以靈活、現代地建立直接擁抱網頁平台的 API。您可以:
- 建立完整的公開 API 供網頁、行動裝置或第三方客戶端使用。
- 代理並自訂對現有外部服務的呼叫。
- 實作可重複使用的「中介層」來處理驗證、日誌記錄或任何重複邏輯。
- 使用
[id]
區段資料夾結構動態路由請求。
常見問題
關於伺服器動作 (Server Actions)?
您可以將伺服器動作視為自動產生的 POST
API 路由,可從客戶端呼叫。
它們專為變更操作設計,例如建立、更新或刪除資料。您可以像呼叫普通 JavaScript 函數一樣呼叫伺服器動作,而不需要對定義的 API 路由進行明確的 fetch
。
雖然仍然會發生網路請求,但您不需要明確管理它。URL 路徑是自動產生並加密的,因此您無法手動存取瀏覽器中的 /api/users
等路由。
如果您計劃使用伺服器動作並公開 API,建議將核心邏輯移至資料存取層,並從伺服器動作和 API 路由呼叫相同的邏輯。
可以在路由處理器中使用 TypeScript 嗎?
是的,您可以在路由處理器中使用 TypeScript。例如,在 route
檔案中定義 Request
和 Response
類型。
了解更多關於 Next.js 中的 TypeScript。
驗證的最佳實踐是什麼?
請參閱我們的驗證文件以了解更多。