中文

学习如何使用 Next.js 路由处理器创建强大的 API 端点。本指南涵盖从基础设置到高级技术的所有内容,并附有实用示例和最佳实践。

Next.js 路由处理器:API 端点创建综合指南

Next.js 以其强大的功能,如服务器端渲染、静态站点生成以及现在的路由处理器 (Route Handlers),彻底改变了我们构建 Web 应用程序的方式。路由处理器提供了一种灵活高效的方式,可以直接在您的 Next.js 应用程序中创建 API 端点。本指南将探讨路由处理器的概念、其优势以及如何有效地使用它们来构建健壮的 API。

什么是 Next.js 路由处理器?

路由处理器是在 Next.js 项目的 app 目录中定义的函数,用于处理传入的 HTTP 请求。与旧的 pages/api 方法(使用 API 路由)不同,路由处理器提供了一种更简化、更灵活的方式来在 React 组件旁定义 API 端点。它们本质上是在边缘或您选择的服务器环境中执行的无服务器函数。

您可以将路由处理器视为 Next.js 应用程序的后端逻辑,负责处理请求、与数据库交互并返回响应。

使用路由处理器的好处

设置您的 Next.js 项目

在深入研究路由处理器之前,请确保您已设置好一个包含 app 目录的 Next.js 项目。如果您要启动一个新项目,请使用以下命令:

npx create-next-app@latest my-nextjs-app

在设置过程中选择 app 目录以启用新的路由系统。

创建您的第一个路由处理器

让我们创建一个返回 JSON 响应的简单 API 端点。在 app 目录中创建一个新目录,例如 /app/api/hello。在此目录中,创建一个名为 route.ts(如果您不使用 TypeScript,则为 route.js)的文件。

这是您的第一个路由处理器的代码:

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

export async function GET(request: Request) {
 return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });
}

代码解释:

现在,您可以通过在浏览器中访问 /api/hello 或使用像 curlPostman 这样的工具来访问此端点。

处理不同的 HTTP 方法

路由处理器支持各种 HTTP 方法,如 GET、POST、PUT、DELETE、PATCH 和 OPTIONS。您可以在同一个 route.ts 文件中为每种方法定义单独的函数。

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

export async function GET(request: Request) {
 // 从数据库检索所有用户的逻辑
 const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // 示例数据
 return NextResponse.json(users);
}

export async function POST(request: Request) {
 const data = await request.json(); // 将请求体解析为 JSON
 // 使用 'data' 在数据库中创建新用户的逻辑
 const newUser = { id: 3, name: data.name, email: data.email }; // 示例
 return NextResponse.json(newUser, { status: 201 }); // 返回新用户,状态码为 201 Created
}

代码解释:

访问请求数据

request 对象提供了对传入请求的各种信息的访问,包括请求头、查询参数和请求体。

请求头 (Headers)

您可以使用 request.headers 属性访问请求头:

export async function GET(request: Request) {
 const userAgent = request.headers.get('user-agent');
 console.log('User Agent:', userAgent);
 return NextResponse.json({ userAgent });
}

查询参数 (Query Parameters)

要访问查询参数,您可以使用 URL 构造函数:

export async function GET(request: Request) {
 const url = new URL(request.url);
 const searchParams = new URLSearchParams(url.search);
 const id = searchParams.get('id');
 console.log('ID:', id);
 return NextResponse.json({ id });
}

请求体 (Request Body)

对于 POST、PUT 和 PATCH 请求,您可以根据内容类型使用 request.json()request.text() 方法访问请求体。

export async function POST(request: Request) {
 const data = await request.json();
 console.log('Data:', data);
 return NextResponse.json({ receivedData: data });
}

返回响应

NextResponse 对象用于构建 API 响应。它提供了几种用于设置响应头、状态码和响应体的方法。

JSON 响应

使用 NextResponse.json() 方法返回 JSON 响应:

return NextResponse.json({ message: 'Success!', data: { name: 'John Doe' } }, { status: 200 });

文本响应

使用 new Response() 构造函数返回纯文本响应:

return new Response('Hello, world!', { status: 200, headers: { 'Content-Type': 'text/plain' } });

重定向

使用 NextResponse.redirect() 将用户重定向到不同的 URL:

import { redirect } from 'next/navigation';
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 return NextResponse.redirect(new URL('/new-location', request.url));
}

设置响应头

您可以使用 NextResponse.json()new Response() 中的 headers 选项设置自定义响应头:

return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });

中间件集成

中间件允许您在请求被路由处理器处理之前运行代码。这对于身份验证、授权、日志记录和其他横切关注点非常有用。

要创建中间件,请在 app 目录或任何子目录中创建一个名为 middleware.ts(或 middleware.js)的文件。该中间件将应用于该目录及其子目录中的所有路由。

// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
 const token = request.cookies.get('auth-token');

 if (!token) {
 return NextResponse.redirect(new URL('/login', request.url));
 }

 return NextResponse.next();
}

export const config = {
 matcher: ['/protected/:path*'], // 将此中间件应用于以 /protected/ 开头的路径
};

代码解释:

错误处理

正确的错误处理对于构建健壮的 API 至关重要。您可以使用 try...catch 块来处理异常并返回适当的错误响应。

export async function GET(request: Request) {
 try {
 // 模拟一个错误
 throw new Error('Something went wrong!');
 } catch (error: any) {
 console.error('Error:', error);
 return NextResponse.json({ error: error.message }, { status: 500 });
 }
}

代码解释:

流式响应

路由处理器支持流式响应,这允许您增量地向客户端发送数据。这对于大型数据集或长时间运行的进程特别有用。

import { Readable } from 'stream';
import { NextResponse } from 'next/server';

async function* generateData() {
 for (let i = 0; i < 10; i++) {
 await new Promise(resolve => setTimeout(resolve, 500)); // 模拟延迟
 yield `Data chunk ${i}\n`;
 }
}

export async function GET(request: Request) {
 const readableStream = Readable.from(generateData());

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

代码解释:

身份验证与授权

保护您的 API 端点至关重要。您可以使用中间件或直接在路由处理器中实现身份验证和授权。

身份验证

身份验证验证发出请求的用户的身份。常见的身份验证方法包括:

这是一个使用中间件进行 JWT 身份验证的示例:

// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import jwt from 'jsonwebtoken';

const secret = process.env.JWT_SECRET || 'your-secret-key'; // 替换为一个强大的、随机生成的密钥

export function middleware(request: NextRequest) {
 const token = request.cookies.get('auth-token')?.value;

 if (!token) {
 return NextResponse.json({ message: 'Authentication required' }, { status: 401 });
 }

 try {
 jwt.verify(token, secret);
 return NextResponse.next();
 } catch (error) {
 return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
 }
}

export const config = {
 matcher: ['/api/protected/:path*'],
};

授权

授权决定了用户被允许访问哪些资源。这通常基于角色或权限。

您可以在路由处理器中通过检查用户的角色或权限来实现授权,如果他们没有访问权限,则返回错误。

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

export async function GET(request: Request) {
 // 假设您有一个函数可以从令牌或会话中获取用户角色
 const userRole = await getUserRole(request);

 if (userRole !== 'admin') {
 return NextResponse.json({ message: 'Unauthorized' }, { status: 403 });
 }

 // 检索管理员数据的逻辑
 const adminData = { message: 'Admin data' };
 return NextResponse.json(adminData);
}

async function getUserRole(request: Request): Promise {
 // 用您的实际逻辑替换,以从请求中提取用户角色
 // 这可能涉及验证 JWT 令牌或检查会话
 return 'admin'; // 示例:为演示目的硬编码的角色
}

部署路由处理器

路由处理器作为无服务器函数部署在您选择的托管提供商上。Next.js 支持各种部署平台,包括 Vercel、Netlify、AWS 等。

对于 Vercel,部署就像将您的 Git 仓库连接到 Vercel 并推送您的代码一样简单。Vercel 会自动检测您的 Next.js 项目并将您的路由处理器部署为无服务器函数。

高级技术

边缘函数 (Edge Functions)

路由处理器可以部署为边缘函数,这些函数在 CDN 的边缘执行,更接近您的用户。这可以显著减少延迟并提高性能。

要将路由处理器部署为边缘函数,请将 edge 运行时添加到您的 route.ts 文件中:

export const runtime = 'edge';

import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 return NextResponse.json({ message: 'Hello from the Edge!' });
}

服务器操作 (Server Actions)

服务器操作允许您直接从 React 组件执行服务器端代码。路由处理器和服务器操作无缝协作,使您能够轻松构建复杂的应用程序。

这是一个使用服务器操作调用路由处理器的示例:

// app/components/MyComponent.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';

async function handleSubmit(data: FormData) {
 'use server';

 const name = data.get('name');
 const email = data.get('email');

 const response = await fetch('/api/users', {
 method: 'POST',
 body: JSON.stringify({ name, email }),
 });

 if (response.ok) {
 router.refresh(); // 刷新页面以反映更改
 }
}

export default function MyComponent() {
 const router = useRouter();

 return (
 




); }

缓存 (Caching)

缓存可以显著提高您的 API 端点的性能。您可以使用 Cache-Control 响应头来控制浏览器和 CDN 如何缓存您的响应。

return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });

此示例将 Cache-Control 响应头设置为 public, max-age=3600,这告诉浏览器和 CDN 将响应缓存一小时。

最佳实践

真实世界示例

以下是一些关于如何使用路由处理器的真实世界示例:

国际电子商务示例:一个路由处理器用于根据用户所在国家/地区检索产品定价。该端点可以使用请求的地理位置(从 IP 地址派生)来确定用户的位置,并以适当的货币返回价格。这有助于提供本地化的购物体验。

全球身份验证示例:一个路由处理器为全球用户实现多因素身份验证 (MFA)。这可能涉及发送短信验证码或使用身份验证器应用程序,同时尊重不同地区的隐私法规和电信基础设施。

多语言内容交付:一个路由处理器以用户的首选语言提供内容。这可以通过请求中的 `Accept-Language` 请求头来确定。此示例强调了在适当情况下需要正确的 UTF-8 编码和对从右到左语言的支持。

结论

Next.js 路由处理器提供了一种强大而灵活的方式,可以直接在您的 Next.js 应用程序中创建 API 端点。通过利用路由处理器,您可以轻松构建健壮的 API,将后端逻辑与 React 组件并置,并利用中间件、流式传输和边缘函数等功能。

这份综合指南涵盖了从基础设置到高级技术的所有内容。通过遵循本指南中概述的最佳实践,您可以构建安全、高性能且可维护的高质量 API。