第2章:RESTful API 基础回顾
说实话,每次接手一个新项目,我看到团队里对 API 风格的理解参差不齐,心里就有点发怵。API 的设计如果一开始就走偏了,后面联调的时候,你会把大半时间花在争吵和返工上。这一章,我们就回到原点,把 REST 最核心的几个概念理清楚。
这一节的内容说白了就是三块:REST 到底在讲究什么?资源怎么命名?HTTP 方法和状态码怎么用才对?搞懂了这些,你才能理解我们后面专门讲的水印接口为什么这么设计。
2.1 REST 架构风格的核心原则
REST 只是一种风格,不是协议,也不是标准库。它的核心在于约定,让客户端和服务端用一种统一、简单的方式沟通。我个人理解,最重要的就是以下几条硬规矩。
- 无状态(Stateless):每一次请求都要包含足够的信息,让服务端能处理它,不需要依赖之前请求留下的任何上下文。相当于你去办事,每次都得带齐身份证、申请表、审批单,窗口不替你记。
- 客户端-服务端(Client-Server):界面和数据处理必须分离。前端只负责展示,后端只管数据。谁也别跨界,独立迭代才快。
- 统一接口(Uniform Interface):这是 REST 最关键的特征。所有资源都通过固定的、通用的接口来操作。说白了,就是用同一套 HTTP 方法(GET/POST/PUT/DELETE)去操作不同的资源,而不是每个功能都发明一个自定义接口。
- 缓存(Cacheable):响应数据要明确告诉客户端能不能缓存。能省一次网络请求,就省一次。
- 分层系统(Layered System):客户端通常不知道它是在直接连接服务端,还是中间经过了负载均衡、API 网关。每层只管自己的事。
我的经验:无状态这一点,我刚开始学 REST 时被绕进去过。当时设计了一个水印任务的状态查询接口,每次调用时都让服务端记住上次的查询进度。后来联调时发现,负载均衡把请求打到节点B上,但状态信息存在节点A里…… 查了半天。从那以后,我的每个请求都老老实实携带完整的 和任务 ID,反而更稳定。
2.2 资源与 URI 设计
REST 的世界里,一切都是资源。图片、水印模板、任务记录,甚至一个用户,都可以看作资源。
URI 就是这些资源的门牌号。设计得好,接口清晰可读;设计得差,你就会在文档里写一堆“请查询第5.3节特殊说明”。
我建议你记住这几条命名原则:
- 使用名词,而非动词。
好的:/api/watermark-tasks
坏的:/api/getTaskInfo - 用复数名词。
好的:/api/images
坏的:/api/image - 层级关系用斜杠分隔。
好的:/api/users/1234/watermark-tasks(表示用户 1234 的水印任务集合) - 用连字符,不用下划线。
好的:/api/image-filters
坏的:/api/image_filters - 查询参数用于过滤、排序、分页,不要用于标识资源。
好的:/api/watermark-tasks?status=pending&page=1
坏的:/api/watermark-tasks?action=getPending
避坑指南:我曾经在一个水印服务的 V1 版本里,把资源路径名写成 /api/get-watermark-position。当时觉得直观,后来要支持批量获取时,这个 URI 就完全没法扩展了,最后只能另起一条路。教训:一开始就用名词复数,别走捷径。
下面这个表格可以帮你快速对比 URI 设计的好与坏:
| 场景 | 坏的 URI | 好的 URI |
|---|---|---|
| 获取水印模板列表 | /api/getAllTemplates | GET /api/watermark-templates |
| 获取单个模板 | /api/template?id=42 | GET /api/watermark-templates/42 |
| 添加水印任务 | /api/submitTaskToQueue | POST /api/watermark-tasks |
| 更新任务状态 | /api/updateTaskStatus | PATCH /api/watermark-tasks/42 |
你看,好的 URI 一眼就知道是什么资源、要做什么操作。坏的那种呢?你得先去看文档,再猜参数。
2.3 HTTP 方法与状态码
URI 只是门牌号,HTTP 方法才是你要对资源做的动作。常用的就那么几个,但搭配错了,就会出问题。
简单整理一下:
- GET – 查询资源。必须是安全的、幂等的。多次查询结果不变。
- POST – 创建资源。非幂等,每次调用都可能新增一条。
- PUT – 全量替换资源。幂等的,你把整张表单重新提交一次。
- PATCH – 部分更新资源。非幂等?一般也是幂等的,但取决于实现。
- DELETE – 删除资源。幂等的,删一次和删十次结果一样。
小技巧:很多人分不清 PUT 和 PATCH 的区别。我在项目中用的标准是:如果你只改一个字段(比如水印透明度),就用 PATCH;如果你要替换整个资源对象,就用 PUT。这样语义清晰,后端也好处理。
状态码则是服务器给你的反馈。别只用 200 和 500,用好这些码能让客户端自动做很多事。
2xx 成功
- 200 OK – 通用成功。GET 查询、PUT 更新成功时用。
- 201 Created – 创建成功。POST 新增资源时用。
- 204 No Content – 删除成功,或者更新成功但不需要返回内容。
4xx 客户端错误
- 400 Bad Request – 请求参数有误,比如缺少必填字段。
- 401 Unauthorized – 身份认证失败,或者没有提供 。
- 403 Forbidden – 已认证但没权限,比如普通用户删除管理员的水印任务。
- 404 Not Found – 资源不存在。
- 409 Conflict – 冲突,比如创建的资源已存在,或版本号不对。
- 422 Unprocessable Entity – 服务端理解请求格式,但语义上有问题,比如水印位置参数超出图片边界。
5xx 服务端错误
- 500 Internal Server Error – 内部异常,最常用的兜底。
- 502 Bad Gateway / 503 Service Unavailable – 通常是网关或服务过载。
我曾经踩过的坑:在设计 V1 水印接口时,我把用户上传图片格式错误的场景返回了 400,但参数格式错误也返回 400。客户端想自动处理时,根本区分不了是图片坏了还是参数写错了。后来我强制统一:参数问题用 400,业务逻辑问题用 422。这样客户端看到 422 就知道是业务校验失败,可以给用户更清晰的提示。
好,到这里,我们就回顾完了 REST 最基础但最重要的三块内容。
为了让你更直观地理解这些概念如何串联起来,我画了一张图,展示了一个典型的 RESTful 水印接口请求从客户端到服务端的完整旅程。
图中左侧是客户端需要遵循的 RESTful 设计规范:怎么写 URI、用什么方法、期望什么状态码。中间是 API 网关集中执行一致性检查。右侧是水印服务内部处理。你会发现,所有环节都围绕着“无状态 + 统一接口”这个核心转。
你以后设计水印接口时,想想这张图你就知道该怎么拆了。