HTTP协议和API设计规范
HTTP协议详解
HTTP(HyperText Transfer Protocol,超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。它是万维网数据通信的基础。
1. 核心特点
- 无连接(早期):早期版本(HTTP/1.0)每次请求响应后都断开TCP连接。现代版本(HTTP/1.1+)默认使用持久连接。
- 无状态:协议本身不对请求和响应之间的状态进行保存。每个请求都是独立的,这简化了服务器设计,但需要通过Cookie、Session等技术来管理状态。
- 基于请求/响应模型:客户端(如浏览器)发起请求,服务器返回响应。
2. 请求报文(Request)
一个HTTP请求由三部分组成:
- 请求行 (Request Line):包含方法、URL和HTTP版本。
GET /api/v1/users HTTP/1.1
- 请求头 (Request Headers):包含关于请求的元数据(metadata)。
Host: api.example.com
User-Agent: Mozilla/5.0...
Authorization: Bearer <token>
Content-Type: application/json
Accept: application/json
- 请求体 (Request Body):可选,主要用于POST、PUT等方法,携带发送给服务器的数据。
3. 响应报文(Response)
一个HTTP响应由三部分组成:
- 状态行 (Status Line):包含HTTP版本、状态码和状态信息。
HTTP/1.1 200 OK
- 响应头 (Response Headers):包含关于响应的元数据。
Content-Type: application/json
Content-Length: 1024
Set-Cookie: sessionId=abc123
- 响应体 (Response Body):可选,包含服务器返回给客户端的实际数据(如HTML、JSON等)。
4. 常用HTTP方法(动词)
方法定义了应对资源执行的操作类型,这是RESTful设计的核心。
- GET:请求一个指定资源的表示形式。只用于获取数据,不应产生副作用。
- POST:将数据提交给服务器,通常会导致创建新资源或执行复杂操作。
- PUT:用请求数据完整替换目标资源。用于更新整个资源。
- PATCH:对资源进行部分更新。
- DELETE:删除指定的资源。
5. 重要HTTP状态码(Status Codes)
状态码指示请求的结果,分为五类:
- 1xx (信息性):请求已被接收,继续处理。
- 2xx (成功):请求已成功被服务器接收、理解并接受。
200 OK
:通用成功状态。201 Created
:资源创建成功。204 No Content
:请求成功,但响应报文中无实体主体(如DELETE成功)。
- 3xx (重定向):需要客户端采取进一步的操作以完成请求。
301 Moved Permanently
:资源已被永久移动到新URL。304 Not Modified
:资源未修改,可使用缓存版本。
- 4xx (客户端错误):请求包含语法错误或无法完成请求。
400 Bad Request
:请求报文存在语法错误。401 Unauthorized
:需要身份认证或认证失败。403 Forbidden
:服务器理解请求,但拒绝执行(权限不足)。404 Not Found
:服务器找不到请求的资源。429 Too Many Requests
:客户端发送的请求过多(限流)。
- 5xx (服务器错误):服务器处理请求时发生错误。
500 Internal Server Error
:通用服务器错误。502 Bad Gateway
:网关或代理服务器从上游服务器收到无效响应。503 Service Unavailable
:服务器暂时过载或维护中。
第二部分:API设计规范(RESTful最佳实践)
基于HTTP协议的API设计,我们通常遵循REST架构风格,即 RESTful API。其核心是将资源(Resource)作为URL路径,通过HTTP方法(动词)来操作资源。
1. 面向资源设计
- 一切皆资源(如用户、订单、文章)。
- 使用名词的复数形式来定义端点(Endpoint),而不是动词。
- 好:
/api/v1/users
、/api/v1/products/123
- 差:
/api/v1/getUser
、/api/v1/createProduct
- 好:
2. 使用HTTP方法表达动作
对同一资源的不同操作,使用不同的HTTP方法。
GET /api/v1/users
-> 获取所有用户列表POST /api/v1/users
-> 创建一个新用户GET /api/v1/users/123
-> 获取ID为123的用户详情PUT /api/v1/users/123
-> 完整更新ID为123的用户PATCH /api/v1/users/123
-> 部分更新ID为123的用户DELETE /api/v1/users/123
-> 删除ID为123的用户
3. 版本控制
将API版本号嵌入URL或HTTP头信息,以便未来进行不兼容的更新时不影响旧客户端。
- URL路径(最常用):
/api/v1/users
- 查询参数:
/api/users?version=1
- 自定义请求头:
Accept: application/vnd.company.api-v1+json
- 我们公司推荐使用URL路径方式,因为它最直观且易于调试。
4. 过滤、排序、搜索和分页
对于返回集合的端点(如GET /api/v1/users
),应提供这些参数来限制和整理结果。
- 过滤:
GET /api/v1/users?role=admin&active=true
(只返回角色是admin且活跃的用户) - 搜索:
GET /api/v1/users?name=John
(搜索名字包含John的用户) - 排序:
GET /api/v1/users?sort=-created_at,name
(按创建时间降序,再按名字升序排序) - 分页:
GET /api/v1/users?page=2&limit=50
(返回第2页,每页50条数据)- 响应中应包含分页元信息,如总条数、总页数等。
5. 响应格式标准化
- 统一使用JSON作为数据交换格式,并设置
Content-Type: application/json
。 - 响应体结构应保持一致。一个良好的实践是使用信封模式。
{"data": { // 成功时,主要数据放在这里"id": 123,"name": "John Doe"},"meta": { // 分页等元信息"total": 1000,"page": 2},"error": { // 失败时,错误信息放在这里"code": "invalid_token","message": "The authentication token is expired."} }
6. 错误处理
- 正确使用HTTP状态码(如400, 401, 403, 404, 500)。
- 提供清晰、详细的错误信息。错误响应体应包含机器可读的错误码和人类可读的描述信息,并可选择包含帮助链接或错误详情。
{"error": {"code": "invalid_request_params","message": "The 'email' field is required and must be a valid email address.","details": [{"field": "email","issue": "required"}]} }
7. 安全性
- 始终使用HTTPS。
- 身份认证:使用标准方案,如JWT(Bearer Token)、OAuth 2.0。通过
Authorization
请求头传递。 - 授权:确保用户只能访问他们有权限的资源。
- 输入验证和清理:永远不要信任客户端输入,防止SQL注入、XSS等攻击。
- 速率限制:防止API被滥用,可通过响应头(如
X-RateLimit-Limit
,X-RateLimit-Remaining
)告知客户端限制情况。
8. 其他最佳实践
- 使用中划线命名URL,使用小驼峰命名JSON属性。
- URL:
/api/v1/user-profiles
- JSON:
{ "firstName": "John" }
- URL:
- 提供API文档:使用OpenAPI(Swagger)等工具生成交互式文档,这是现代API开发的标配。
- 选择合适的HTTP状态码,不要滥用
200 OK
来返回错误。
面试官提问环节
以上就是我对HTTP协议和API设计规范的详细介绍。基于这些内容,我有几个问题想请你回答:
- 情景题:假设你设计了一个
POST /api/v1/articles
接口来创建文章。如果用户提交的数据不完整(例如缺少必填的title
字段),你应该返回什么HTTP状态码?响应体里应该包含什么信息? - 设计题:如果需要设计一个API端点,它既能根据关键词搜索用户,又能根据部门进行过滤,这个端点的URL和参数应该怎么设计?
- 对比题:
PUT
和PATCH
方法在更新资源时有什么区别?请举例说明。 - 实践题:为了防止API被恶意爬虫刷接口,你会从哪些方面着手?
请思考并回答。