首页/14

14章:Next.js API路由:给博客装上后端

在同一个项目中构建RESTful API,让前端和后端共享类型

50分钟
4个学习目标

学习目标

  • 1理解API路由的概念和使用场景
  • 2学会创建RESTful API端点
  • 3掌握请求处理(查询参数、请求体、请求头)
  • 4了解数据验证的重要性

回顾与问题引入

上一章我们学会了用Next.js创建页面。现在博客有了"门面"——首页、文章详情页、关于页面。但是有一个问题:页面上的数据是硬编码的

你可能会想:我怎么让页面从数据库获取数据?怎么让用户提交表单?怎么实现"删除文章"这种操作?

答案是:API路由。

类比理解:

想象你的博客是一家餐厅:

  • 页面(上一章学的)= 餐厅的菜单和装修
  • API路由(本章学的)= 厨房,处理"做菜"的逻辑

客人(前端)通过菜单(页面)下单,厨房(API)处理订单,然后把做好的菜(数据)送回去。

API路由解决的问题:

  • 前端需要获取数据(GET请求)
  • 用户需要提交表单(POST请求)
  • 用户需要修改数据(PUT请求)
  • 用户需要删除数据(DELETE请求)

什么是API路由?

Next.js允许你在同一个项目中创建API端点,不需要单独搭建后端服务器。

传统方式 vs Next.js方式:

| 方面 | 传统方式 | Next.js方式 | |------|---------|------------| | 项目结构 | 前端项目 + 后端项目 | 一个项目 | | 部署 | 分别部署 | 统一部署 | | 类型共享 | 需要额外配置 | 天然共享 | | 开发效率 | 需要切换上下文 | 在一个地方完成 |

API路由的文件位置:

app/
├── api/              # API路由目录
│   ├── users/
│   │   └── route.ts  # /api/users
│   └── posts/
│       ├── route.ts      # /api/posts
│       └── [id]/
│           └── route.ts  # /api/posts/:id

关键规则:

  • API路由放在app/api/目录下
  • 文件名必须是route.ts
  • 导出命名函数:GET、POST、PUT、DELETE

创建第一个API端点

typescript
加载中...

动态API路由:处理单个资源

有时候你需要处理单个资源——比如获取ID为1的文章、更新ID为2的文章。这需要用到动态路由参数

类比理解:

动态API路由就像快递柜

  • /api/posts → 快递柜的总入口(查看所有快递)
  • /api/posts/123 → 123号柜子(查看特定快递)

参数获取方式:

export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const id = params.id; // 获取URL中的id参数
}

注意:第二个参数是一个对象,包含params属性。

动态API路由实战

typescript
加载中...

请求处理:获取客户端发送的数据

API需要接收客户端发送的数据。根据请求类型,获取数据的方式不同:

三种常见数据来源:

| 数据来源 | 获取方式 | 使用场景 | |----------|---------|---------| | 查询参数 | new URL(request.url).searchParams | 搜索、分页、过滤 | | 请求体 | request.json() | 表单提交、创建/更新数据 | | 请求头 | request.headers.get("Authorization") | 认证、内容类型 |

类比理解:

  • 查询参数 = 快递单上的备注("请放门口")
  • 请求体 = 快递里面的东西(实际的包裹)
  • 请求头 = 快递单上的发件人信息(谁寄的)

处理不同类型的数据

typescript
加载中...

数据验证:永远不要相信客户端

这是一个重要的安全原则:永远不要相信客户端发送的数据

用户可能发送:

  • 空的标题
  • 超长的内容
  • 恶意的HTML代码
  • 不合法的邮箱格式

类比理解:

数据验证就像机场安检

  • 所有行李(数据)都要过安检(验证)
  • 不合格的行李会被拦截(返回400错误)
  • 合格的行李才能进入候机厅(进入业务逻辑)

推荐使用Zod库: Zod是TypeScript优先的数据验证库,语法简洁,类型推断强大。

使用Zod进行数据验证

typescript
加载中...

常见错误

常见错误

错误1:忘记导出命名函数

// 错误!函数名必须是 GET、POST、PUT、DELETE
export default function handler() {} // 不工作

// 正确
export async function GET() {}

错误2:文件名不是route.ts

// 错误!app/api/hello.ts 不会创建API路由
// 正确:app/api/hello/route.ts

错误3:忘记await request.json()

// 错误!request.json() 返回 Promise
const body = request.json(); // body 是 Promise,不是对象

// 正确
const body = await request.json(); // body 是解析后的对象

错误4:在GET请求中读取请求体

// 错误!GET请求通常没有请求体
export async function GET(request: Request) {
  const body = await request.json(); // 可能报错
}

// 正确:GET请求使用查询参数
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const page = searchParams.get("page");
}

错误5:没有处理错误情况

// 危险!没有try-catch
export async function POST(request: Request) {
  const body = await request.json(); // 如果请求体不是JSON会崩溃
}

// 安全
export async function POST(request: Request) {
  try {
    const body = await request.json();
    // ...
  } catch (error) {
    return NextResponse.json({ error: "请求格式错误" }, { status: 400 });
  }
}

动手实践

现在轮到你了!让我们动手练习:

练习1:创建用户API 创建一个完整的用户CRUD API:

  • GET /api/users - 获取所有用户
  • POST /api/users - 创建用户
  • GET /api/users/[id] - 获取单个用户
  • PUT /api/users/[id] - 更新用户
  • DELETE /api/users/[id] - 删除用户

练习2:添加搜索功能 创建一个搜索API:

  • GET /api/posts/search?q=keyword
  • 根据关键词搜索文章标题和内容
  • 返回匹配的文章列表

练习3:数据验证 使用Zod验证用户输入:

  • 验证邮箱格式
  • 验证密码长度(至少8位)
  • 验证用户名(只能包含字母和数字)

提示:

  • 使用NextResponse.json()返回JSON响应
  • 使用{ status: 400 }返回错误状态码
  • 使用try-catch处理可能的错误

本章总结

恭喜你完成了Next.js API路由的学习!让我们回顾一下:

本章学到的:

  1. API路由让前后端写在一个项目里,共享TypeScript类型
  2. 文件放在app/api/目录下,文件名必须是route.ts
  3. 导出GET、POST、PUT、DELETE函数处理不同请求
  4. 使用Zod进行数据验证,永远不要相信客户端

前后对比:

| 方面 | 之前(无API) | 现在(有API) | |------|-------------|-------------| | 数据来源 | 硬编码在页面中 | 从API获取 | | 用户交互 | 只能展示 | 可以提交表单、修改数据 | | 项目结构 | 只有前端 | 前后端一体化 | | 类型安全 | 页面内部 | 前后端共享类型 |

下一章预告:

有了页面和API,我们的博客还需要可复用的React组件。下一章我们将学习如何用TypeScript构建React组件——按钮、卡片、表单,让你的博客更专业。

交互式练习

1 / 1

创建文章API

创建一个GET /api/posts端点,返回文章列表

typescript
Loading...

章节测验

问题 1 / 3得分: 0 / 3

Next.js API路由文件放在哪个目录?

A
pages/api/
B
app/api/
C
src/api/
D
api/