Next.js Route Handlers (API 路由)

Route Handlers 是 Next.js App Router 中用來建立 Web API 的機制。它們允許你針對特定的路由定義 HTTP 方法(如 GET, POST 等),並回傳自定義的 Response。

這是在 Next.js 中建立後端邏輯的標準方式,取代了過去 Pages Router 的 pages/api

適用場景 (When to use?)

  1. 公開 API (Public API):提供 JSON 資料給行動裝置 App 或第三方開發者。
  2. Webhooks:接收外部服務(如 Stripe 還有 LINE Bot)的事件通知。
  3. 非 JSON 回應:需要動態生成 RSS Feed、圖片或 sitemap.xml
  4. 代理請求 (Proxying):隱藏 API Key,由 Server 端轉發請求給第三方服務。
如果你只是要讓自己的前端 React Components 存取資料或提交表單,Server Actions 通常是更好的選擇,因為它更簡潔且不需要手動處理 API 路由。

定義路由 (Basic Usage)

Route Handlers 定義在 app 目錄下的 route.ts (或 .js) 檔案中。

檔案結構範例:

  • app/api/users/route.ts -> URL: /api/users
  • app/auth/callback/route.ts -> URL: /auth/callback

基礎語法

你需要匯出與 HTTP 方法同名的 async 函式:

// app/api/hello/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({ message: 'Hello World' });
}

export async function POST(request: Request) {
  const body = await request.json();
  return NextResponse.json({ received: body });
}

支援的方法:GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS

處理請求 (Request Object)

Next.js 擴充了標準 Web Request API,提供了 NextRequest 物件,讓你更容易讀取 URL 參數、Cookies 和 Headers。

讀取 URL 參數 (Query Parameters)

常見誤區:Route Handlers 不像 Page props 那樣直接從參數拿 query,而是要從 request.nextUrl 解析。

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

export function GET(request: NextRequest) {
  // 取得 /api/search?q=nextjs 中的 q
  const searchParams = request.nextUrl.searchParams;
  const query = searchParams.get('q');

  return NextResponse.json({ query });
}

讀取 Body 資料

export async function POST(request: NextRequest) {
  // 1. 讀取 JSON
  const json = await request.json();

  // 2. 讀取 FormData (例如上傳檔案)
  // const formData = await request.formData();

  // 3. 讀取純文字 (例如 Webhook 簽章驗證)
  // const text = await request.text();

  return NextResponse.json({ status: 'ok' });
}

讀取 Cookies 與 Headers

import { cookies, headers } from 'next/headers'; // 推薦使用 helper functions

export async function GET(request: NextRequest) {
  // 方法 A: 從 request 物件讀取 (唯讀)
  const userAgent = request.headers.get('user-agent');

  // 方法 B: 使用 next/headers helper (更方便)
  const cookieStore = cookies();
  const token = cookieStore.get('token');

  const headersList = headers();
  const referer = headersList.get('referer');

  return NextResponse.json({ userAgent, hasToken: !!token });
}

動態路由參數 (Dynamic Route Segments)

就像 Page 一樣,Route Handlers 也可以透過資料夾名稱 [slug] 來擷取路徑參數。這些參數會作為第二個引數傳入函式。

路徑app/api/products/[id]/route.ts

export async function GET(request: NextRequest, { params }: { params: { id: string } }) {
  const productId = params.id;

  return NextResponse.json({
    id: productId,
    name: `Product ${productId}`,
  });
}

回應處理 (Response)

回傳 JSON

return NextResponse.json({ data: 'Foo' }, { status: 200 });

轉址 (Redirect)

import { redirect } from 'next/navigation';

export async function GET(request: NextRequest) {
  redirect('https://google.com'); // 拋出 error 中斷執行並轉址
}

串流回應 (Streaming)

這對於生成 AI 回應或大量資料傳輸非常有用。

// app/api/stream/route.ts
export async function GET() {
  const stream = new ReadableStream({
    async start(controller) {
      const encoder = new TextEncoder();
      // 模擬逐步傳送資料
      for (let i = 0; i < 5; i++) {
        await new Promise((r) => setTimeout(r, 500));
        controller.enqueue(encoder.encode(`Chunk ${i}\n`));
      }
      controller.close();
    },
  });

  return new Response(stream, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  });
}

快取行為 (Caching)

這是最容易讓人困惑的地方。Next.js 的 GET Route Handlers 預設會有不同的快取行為:

  • 預設快取 (Static):如果 GET 方法沒有使用 Request 物件,也沒有使用動態函式 (cookies, headers),Next.js 會在 build time 靜態生成結果並快取。
  • 動態執行 (Dynamic):如果用了 Request 物件、cookies() 或是在開發模式,則會變成動態渲染。

若要強制指定行為,可以使用 Route Segment Config:

// 強制為動態 (Dynamic),每次請求都重新執行
export const dynamic = 'force-dynamic';

// 或者設定 Revalidation 時間 (ISR)
// export const revalidate = 60; // 每 60 秒更新一次

CORS (跨域資源共享)

如果你的 API 需要被其他網域的前端呼叫,你需要處理 CORS 預檢請求 (Preflight)。

// app/api/cors/route.ts
export async function OPTIONS() {
  return new Response(null, {
    status: 204,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    },
  });
}

export async function GET() {
  return NextResponse.json(
    { data: 'Public Data' },
    {
      headers: { 'Access-Control-Allow-Origin': '*' },
    }
  );
}

小結

Route Handlers 為 Next.js 提供了完整的後端開發能力。

  • 使用 app/api/.../route.ts 定義。
  • 透過 NextRequest 讀取 searchParamsbody
  • 支援標準 Web API (Response, ReadableStream)。
  • 留意 GET 的預設快取行為,必要時使用 export const dynamic = 'force-dynamic'

掌握了 Route Handlers,你就能在 Next.js 專案中輕鬆構建全功能的 RESTful API 或 Webhook 處理器。