HTTP协议与请求方法归纳总结
聊SDK缓存架构,绕不开HTTP协议。
你想想看,SDK的API调用本质就是HTTP请求。我做了多年前后端,见过不少团队把缓存设计得很复杂,结果问题往往出在最基础的HTTP方法理解上。今天我们就掰开揉碎,把HTTP协议和请求方法彻底讲清楚。
1. HTTP协议核心:无状态但有语义
HTTP本身是无状态的。每次请求都是独立的,服务器不记住你上一次干了什么。但RESTful API设计赋予了它语义——通过请求方法、状态码、头部信息表达意图。
举个例子:你调用一个获取用户信息的接口,用GET还是POST?很多人觉得无所谓,但我说,这能决定你的缓存策略是否有效。我在项目中遇到过因为用POST做查询,导致缓存完全失效的惨案。
核心原则: 请求方法决定了请求的幂等性和安全性,进而影响缓存行为。
2. 请求方法详解
先看一张表,把主流方法的特性理清楚。
| 方法 | 语义 | 幂等 | 安全 | 可缓存 | 典型场景 |
|---|---|---|---|---|---|
| GET | 获取资源 | 是 | 是 | 是 | 查询用户、列表等 |
| POST | 创建资源 | 否 | 否 | 仅支持新鲜度校验 | 新增订单、注册 |
| PUT | 全量更新 | 是 | 否 | 否 | 替换用户信息 |
| PATCH | 部分更新 | 否 | 否 | 否 | 修改用户昵称 |
| DELETE | 删除资源 | 是 | 否 | 否 | 删除文章 |
| HEAD | 获取响应头 | 是 | 是 | 是 | 预检、缓存校验 |
| OPTIONS | 查询支持的方法 | 是 | 是 | 否 | CORS预检 |
这里有两个关键概念:幂等和安全。
- 安全方法:不会修改服务器状态,比如GET和HEAD。你调用一万次,数据不变。
- 幂等方法:无论调用多少次,结果和调用一次相同。PUT、DELETE是幂等的——但注意POST不是。
为什么我要强调这个?因为缓存系统通常只缓存安全且幂等的方法。但你看看PATCH,它既不是安全的也不是幂等的,浏览器和代理默认不会缓存它。你在SDK中如果误用PATCH做更新后的查询,缓存层直接跳过。
避坑指南: 我曾经在一个项目中,同事用POST做复杂查询,还加了Cache-Control头。结果因为POST默认不可缓存,缓存一直不命中,服务端压力巨大。后来改成GET + body(虽然不规范),配合ETag,性能才上来。
3. 缓存相关的HTTP头部
SDK缓存架构的核心,就是利用HTTP头部控制缓存行为。说几个必知必会的。
| 头部 | 说明 | 示例 |
|---|---|---|
Cache-Control |
指定缓存策略,如max-age=3600 |
Cache-Control: public, max-age=3600 |
ETag |
资源版本标识符,用于条件请求 | ETag: "abc123" |
Last-Modified |
资源最后修改时间 | Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT |
Expires |
过期时间(HTTP/1.0,已被Cache-Control取代) | Expires: Thu, 01 Dec 2023 16:00:00 GMT |
Vary |
根据请求头区分缓存版本 | Vary: Accept-Encoding |
我个人习惯在SDK的HTTP客户端里设置默认的Cache-Control策略。对于GET请求,如果服务端没有返回缓存头,客户端可以按业务规则补一个max-age=60作为兜底。但要注意,这需要和服务端约定好。
4. 请求方法与缓存决策流程图
下面这张图,把缓存决策逻辑串起来。你对照着看,SDK里的缓存中间件干的就是这个事。
实战建议: 在上图流程中,SDK的缓存层应该对GET请求先检查本地缓存的有效性。如果缓存过期但ETag还在,可以用条件请求(
If-None-Match)减轻服务端压力。我自己的SDK里,这部分逻辑通常写成一个拦截器,对所有GET请求生效。
5. 实践中的常见陷阱
最后聊几个坑。我说过,SDK设计的好坏,往往体现在对异常和边界的处理上。
- POST请求被缓存中间件拦截: 有些团队在SDK中引入统一缓存层,对所有请求都查询缓存。结果POST创建请求被错误地返回了旧数据。解决办法:在缓存中间件里按方法白名单过滤。
- 忽略
Vary头: 如果服务端返回了Vary: Authorization,而你的SDK缓存没考虑这个,不同用户的请求可能共享同一个缓存条目,导致数据泄露。这是个安全漏洞。 - ETag配对失误: 服务端换了资源但ETag没变,客户端缓存一直命中旧数据。我建议在SDK缓存中加入
stale-while-revalidate策略:先返回旧数据,同时在后台异步刷新。 - 缓存写入时机不对: 有些SDK在收到响应后就写入缓存,但没检查响应状态码。如果服务器返回了500,你也缓存进去,后续所有请求都拿错误结果。必须只缓存2xx和3xx响应。
严重警告: 不要在SDK中缓存包含敏感信息的响应到持久化存储(如文件、SQLite)。除非你做了加密且安全策略明确。否则一旦用户手机被root,数据就裸奔了。