先记住这个答案
GET请求获取资源,安全且幂等,不改变服务器状态,因此可被浏览器、代理或CDN缓存;POST请求提交数据,可能产生副作用,不安全不幂等,默认不可缓存。其本质区别是HTTP方法语义的差异,决定了请求的预期影响、重试行为和缓存策略。
- GET安全幂等,POST不安全非幂等
- GET默认可缓存,POST需显式条件
- POST可缓存需显式新鲜度与Content-Location
语义决定缓存契约
HTTP方法语义定义了请求的预期影响。GET表示获取资源,服务器不改变状态,因此可安全重试和缓存。POST表示提交数据,可能对服务器资源造成变更,因此非安全且非幂等。幂等性指同一请求执行多次与执行一次的效果相同,GET天然满足,POST需谨慎设计。
缓存行为是语义的延伸。浏览器和代理缓存通常只存储GET响应,因为可用作后续GET的回复。POST默认不可缓存,因为响应可能依赖请求体或造成副作用。HTTP规范允许POST缓存,但要求响应包含新鲜度信息如Cache-Control或Expires,并带有Content-Location头表示缓存标识。
后撒返回时的请求重放
用户在电商搜索页(GET)点击商品详情,然后使用POST提交订单。点击浏览器后退返回搜索页,浏览器可能显示缓存页面而不发送新GET;若再前进到订单提交页,浏览器会提示用户是否重新发送POST,因POST非幂等,重放可能导致重复下单。
解决方案是采用POST后重定向到GET模式:订单提交后服务器返回303 See Other,重定向到订单确认GET资源。这样刷新或后退时重放的只是GET请求,避免重复提交,且GET响应可缓存,提升响应速度。但这要求服务器正确处理重定向和缓存头。
语义被忽略的边界条件
工程中常见用GET实现搜索但参数含敏感信息,或POST仅查询不修改。前者会致URL泄露,应改用POST或对数据进行加密;后者违反语义,可能影响HTTP基础层的缓存行为。过度依赖约定而忽略方法语义会造成异常。
当POST响应需被缓存时,必须满足规范条件。若服务器返回200但缺少Content-Location和明确新鲜度头,缓存无法识别。此时若要支持分享等场景,可在响应体返回资源URL,客户端随后GET获取。权衡是增加一次请求,但语义清晰。
容易答错的地方
- 以为GET不能带请求体
- HTTP规范未禁止GET带body,但语义定义为获取资源,带body无意义且许多服务器或中间件会忽略或丢弃。在浏览器fetch API中,GET请求若设置body通常会被拒绝或忽略,依赖此特性会破坏缓存和重试逻辑,应避免。
- 认为POST响应绝对不可缓存
- HTTP规范允许POST可缓存,条件是响应含显式新鲜度信息和Content-Location头。例如,更新资源后返回201及新资源的状态,若在CDN等中间层正确配置,也可能被缓存。实践中常依赖GET透明提升性能,但POST并非完全不可缓存。
面试官还会怎么问?
安全方法与幂等方法有何区别?
安全方法不修改资源状态,GET是安全方法;幂等方法指重复请求与一次请求效果相同,PUT和DELETE是幂等方法,但不安全。安全方法侧重无副作用,幂等方法强调可重试性。
POST请求如何实现可靠的重试?
可引入客户端生成的请求唯一编号(Idempotency-Key),服务器记录编号并去重,或采用异步模式:POST返回202 Accepted,客户端稍后通过资源URL查询处理结果。需权衡一致性与复杂度。
缓存GET响应时,为什么有时需要Vary头?
GET响应可能因用户代理、语言、编码等不同,Vary头告诉缓存根据哪个请求头区分存储。若忽视Vary,缓存可能向错误用户返回错误版本。例如响应依赖Accept-Language,必须发送Vary字段。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。