本节目标:当接口越来越多、使用者越来越多时,了解怎么让接口从"能用"变成"好用"——文档、版本管理、批量操作、文件上传、实时更新。
每次写前端代码,小明都要打开后端文件夹,一个个翻 route.ts 文件,确认"这个接口叫什么、要传什么参数、返回什么格式"。有时候他记错了参数名——把 movieId 写成了 movie_id,调了半天才发现是拼写问题。
更尴尬的是,他的朋友老王想基于他的电影数据做一个"年度观影报告"小程序。老王问:"你的 API 文档在哪?我需要知道有哪些接口、怎么调用。"
小明愣住了——他没有文档。他只能打开微信,一个接口一个接口地告诉老王:"电影列表是 GET /api/movies,支持 page、limit、tag、sort 这些参数……"发了二十多条消息,老王说:"你就不能给我一个文档链接吗?"
你不需要手写文档。业界有一个标准格式叫 OpenAPI(以前叫 Swagger),专门用来描述 API 接口——每个接口的 URL、HTTP 方法、请求参数、响应格式、错误码,全部用结构化的方式定义。
生成 OpenAPI 文档后,可以用 Swagger UI 渲染成一个可交互的网页。这个网页不只是"看"——你可以直接在页面上填参数、点"发送",实时测试每个接口。就像一个内置的 Postman。
这对你自己也有好处:不用再翻代码确认接口细节了,打开文档页面一目了然。
跟 AI 说:
"帮我根据现有的所有 API Route 生成 OpenAPI 3.0 文档。然后加一个
/api-docs页面用 Swagger UI 展示,开发环境可以直接在页面上测试接口。"
最怕的是文档写好了,但后来改了接口忘了更新文档。解决方式是让文档从代码自动生成——每次接口代码变了,文档自动更新。跟 AI 说"用 next-swagger-doc 或类似工具,从 route.ts 文件自动生成 OpenAPI 文档",它会帮你配好自动化流程。
小明想做一个"批量删除"功能——用户在列表页勾选多部电影,点"删除选中",一次性删掉。
最直觉的做法是前端循环调用:
for (const id of selectedIds) {
await fetch(`/api/movies/${id}`, { method: 'DELETE' })
}
50 部电影,50 个 DELETE 请求。能跑,但有三个问题:
慢。 50 个请求意味着 50 次网络往返。即使每次只要 50ms,加起来也要 2.5 秒。用户点了"删除"后要等好几秒才能看到结果。
不一致。 删到第 30 个时网络断了,前 30 个删了,后 20 个没删。数据处于一个"半完成"的尴尬状态——用户以为全删了,实际上还剩 20 个。
浪费资源。 50 个请求占用 50 次数据库连接(虽然很短),在高并发时会加剧连接池的压力。
更好的做法是提供一个批量操作接口:
DELETE /api/movies/batch
请求 body 里带上要删除的 ID 列表:{ "ids": [1, 3, 5, 7, 9, ...] }
后端在一个数据库事务里完成所有删除——要么全删成功,要么全部回滚,不会出现"删了一半"的情况。而且只有一次网络往返,速度快得多。
同样的思路适用于批量更新(比如"把选中的电影全部标记为已看")和批量创建(比如"从 CSV 导入 100 部电影")。
判断标准:当你发现前端在循环调用同一个接口时,就该考虑是不是需要一个批量版本。
跟 AI 说:
"帮我加一个批量删除电影的接口
DELETE /api/movies/batch,接收 ID 数组(最多 100 个),在一个数据库事务里完成删除。如果任何一条删除失败(比如 ID 不存在),全部回滚并返回错误信息。"
不要让用户一次删 10 万条——这会导致事务太大、锁表时间太长、甚至内存溢出。给批量接口加一个上限(比如一次最多 100 条),超过了让前端分批调用。
小明加了评论功能。用户 A 发了一条评论,用户 B 要刷新页面才能看到。小明想做成"不用刷新就能看到新评论"的效果——就像微信聊天一样,消息实时出现。
实时更新有三种方案,复杂度递增:
最简单的方案:前端每隔几秒自动请求一次接口,看有没有新数据。
每 10 秒:GET /api/movies/1/comments?since=上次请求的时间戳
好处是实现极其简单——就是一个 setInterval 加一个 fetch,不需要任何额外的基础设施。
坏处是浪费资源。大部分请求返回的都是"没有新数据"。如果有 1000 个用户同时在线,每 10 秒就是 100 个请求/秒,其中 99% 是无用的。
但对于小明的电影评论来说,轮询完全够用——评论不是高频操作,每 10-30 秒查一次新评论,用户体验完全可以接受。
服务器主动推送数据给前端。前端建立一个长连接,服务器有新数据时主动推过来,不需要前端反复请求。
单向的:只有服务器能推,前端不能通过这个通道发消息。适合"通知推送""新评论提醒""订单状态更新"这类场景——服务器有新消息就推给你,你不需要回复。
好处是实时性好、资源消耗低——只有真正有新数据时才传输,没有无用请求。而且基于 HTTP,不需要额外的协议支持,部署简单。
前端和服务器之间建立一个持久的双向通道,双方都能随时发消息。
适合需要频繁双向通信的场景——在线聊天、协同编辑(多人同时编辑一个文档)、实时游戏。这些场景里,不只是服务器要推数据给前端,前端也要频繁发数据给服务器。
坏处是复杂度高——需要处理连接断开重连、心跳检测、消息顺序保证等问题。部署也更复杂,需要支持 WebSocket 的服务器。
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 评论列表、通知提醒 | 轮询或 SSE | 更新频率低,单向推送就够 |
| 数据看板(每分钟更新) | 轮询 | 更新频率低,轮询最简单 |
| 订单状态实时更新 | SSE | 服务器推送,不需要前端回复 |
| 在线聊天 | WebSocket | 需要双向实时通信 |
| 协同编辑 | WebSocket | 需要双向实时通信 + 冲突处理 |
| 实时游戏 | WebSocket | 需要极低延迟的双向通信 |
一个简单的判断标准:如果只需要服务器推数据给前端,用 SSE。如果前端也需要频繁发数据给服务器,用 WebSocket。如果更新频率低(几秒到几分钟一次),轮询最省事。
小明的评论功能,轮询就够了:
"评论列表需要自动刷新,每 15 秒检查一次有没有新评论。用 SWR 的 refreshInterval 实现自动轮询,不需要手写 setInterval。只返回上次请求之后新增的评论。不需要 WebSocket。"
你跟 AI 说"做一个自动刷新的评论列表",加载了 vercel-react-best-practices Skill 的 Claude Code 大概率会用 SWR 或 TanStack Query(以前叫 React Query)这类数据请求库。两者都自带请求去重(同一个页面多个组件用同一份数据,只发一次请求)、自动缓存、组件卸载时自动清理、失败自动重试。比手写 setInterval + fetch 省心得多,也不容易出"页面切走了但请求还在发"的 bug。
SWR 更轻量,API 更简洁,Vercel 团队维护。TanStack Query 功能更丰富,支持更复杂的缓存策略、乐观更新、无限滚动等场景。对于小明的评论轮询,两个都绰绰有余。你不需要了解它们的用法,AI 会根据项目情况选一个合适的——看到它们出现在代码里不用觉得奇怪。
API 搭好了,但现在谁都能调你的接口——没有登录、没有权限控制。去 第八章:谁能访问我的数据 学习认证和安全。