REST(Representational State Transfer)是一种基于资源的软件架构风格。在于通过统一的接口和标准协议,构建可扩展、松散耦合且高效的分布式系统。理解并遵循其约束是设计高质量 API 的基础。
约束包括:
无状态性:每个客户端请求必须包含服务器处理该请求所需的所有上下文信息。服务器不应在请求之间存储任何会话状态。会话状态应完全由客户端维护,例如通过令牌或在请求体中传递必要参数。这一约束显著提升了系统的可见性、可靠性及可扩展性。
统一接口:这是 REST 最核心的约束,它通过标准化交互方式来简化系统架构。其子原则包括:
资源标识:每个可标识的实体(用户、订单等)都被定义为资源,并拥有一个唯一的标识符——URI。
通过表述操作资源:客户端不与资源直接交互,而是通过资源的表述(如 JSON、XML)来操作。同一资源可以有不同的表述形式。
自描述消息:每个请求或响应消息都必须包含足够的信息,以便接收方能够处理它。这主要通过标准的 HTTP 方法、头部和媒体类型来实现。
超媒体作为应用状态引擎:API 的响应中应包含指向相关资源的链接,引导客户端发现后续可执行的操作。这使得 API 具有了可发现性和动态演化能力。
客户端-服务器分离:客户端和服务器作为独立的组件,通过统一的接口进行通信。这种关注点分离允许两端各自独立发展和优化。
可缓存:响应必须明确标示自身是否可被缓存,以及缓存策略。这有助于消除部分客户端-服务器交互,从而提升性能。
分层系统:架构可以由多个层级组成(如负载均衡器、代理、安全层)。客户端无需了解它是否直接与终端服务器通信,这提高了系统的独立性和可管理性。
资源导向的设计规范
API 的设计应围绕“资源”展开
URI 命名规范:使用名词的复数形式来命名资源集合,例如 /users、/orders。资源之间的层级关系应通过路径嵌套来表达,例如 GET /users/{userId}/orders 用于获取特定用户的所有订单。为提高可读性,建议使用连字符 - 分隔单词,例如 /api-keys,并全程使用小写字母。
HTTP 方法的语义化使用:必须严格遵循 HTTP 方法的语义。
GET:用于安全地检索资源的表述。该操作是幂等的,不应产生副作用。
POST:用于创建新资源或执行不满足其他方法语义的复杂操作。该操作是非幂等的。
PUT:用于执行资源的完整更新。要求客户端提供更新后的完整资源表述。该操作是幂等的,也可用于在已知资源标识符时的创建操作。
PATCH:用于执行资源的局部更新。客户端仅需提供需要修改的字段。该操作是非幂等的。
DELETE:用于删除指定的资源。该操作是幂等的。
请求与响应
HTTP 状态码的精准应用:状态码是服务器与客户端通信的重要部分。
200 OK 表示通用成功。
201 Created 表示资源创建成功,响应头 Location 应包含新资源的 URI。
204 No Content 表示请求成功,但响应体无内容,常用于 DELETE 或 PUT 操作。
400 Bad Request 表示服务器因客户端错误(如畸形请求语法)无法处理请求。
401 Unauthorized 表示请求缺乏有效的身份认证凭证。
403 Forbidden 表示服务器理解请求但拒绝授权,与认证状态无关。
404 Not Found 表示请求的资源在服务器上不存在。
409 Conflict 表示请求与资源的当前状态发生冲突。
500 Internal Server Error 表示服务器遇到了未曾预料的错误。
数据交换格式:JSON 是当前事实上的标准。请求和响应的 Content-Type 头部应明确设置为 application/json。
响应体结构标准化:
对于成功响应,建议将主要数据包裹在一个顶层对象(如 data)中,以便未来添加分页或元数据。
对于错误响应,应提供结构化的错误信息,至少包含错误代码、人类可读的消息以及可能的相关资源字段。
对于资源集合,必须实现分页。常见的模式是使用 offset 和 limit 参数,并在响应中返回总数及指向下一页和上一页的链接。
高级特性与生产环境
API 版本控制:为防止破坏性变更影响现有客户端,必须对 API 进行版本化管理。最清晰和常用的方法是将版本号嵌入 URI 路径,例如 /api/v1/users。其他方法包括使用自定义的 Accept 请求头。
认证与授权:
API 令牌:是一种简单有效的方式,通常在 Authorization: Bearer 头部中传递。
OAuth 2.0:是委托授权的行业标准协议,特别适用于第三方应用访问用户数据。
充分利用 HTTP 头部:
Accept 头用于内容协商,指定客户端期望的响应格式。
ETag 和 If-None-Match 头用于实现条件请求和高效的缓存验证。
超媒体控制:在响应中嵌入链接关系(例如 rel 和 href),使客户端能够动态发现可用的操作,从而降低与 API 的耦合度。
安全和运维
强制使用 HTTPS:所有 API 通信都必须通过 TLS 加密,以保护数据传输的机密性和完整性。
输入验证与清理:对所有输入数据进行严格的验证和清理,以防止注入攻击。
速率限制:对客户端在特定时间窗口内的请求次数进行限制,以保护后端服务免受滥用和拒绝服务攻击。
全面的日志记录与监控:记录所有关键操作的审计日志,并监控 API 的可用性、性能及错误率。