GET 和 POST 有什么区别?
按 HTTP 规范,GET 是安全且幂等的方法,用来读取资源,参数通常放在 URL 里,响应默认可以缓存;POST 不安全也不幂等,用来提交数据,数据放在请求体里,响应一般不缓存。“GET 有长度限制”来自浏览器和服务器对 URL 的限制,“POST 更安全”只是参数不出现在地址栏,不加密,安全要靠 HTTPS。
简答
打开商品详情页是 GET,提交订单是 POST,这已经说出了两者最根本的区别:GET 用来读取,POST 用来提交。HTTP 规范 RFC 9110 把 GET 定义为安全方法,意思是它不应该改变服务器上的数据;还是幂等的,同一个请求发一次和发十次效果一样。POST 两样都不是,提交两次订单可能就下了两单。
从这个语义出发,才有了那些常见区别。GET 的参数一般放在 URL 的查询字符串里,没有请求体;POST 的数据放在请求体里,可以是表单、JSON 或文件。GET 的响应默认可以被浏览器和 CDN 缓存,也能被收藏、分享、出现在历史记录里;POST 的响应一般不缓存,刷新页面时浏览器还会提示是否重新提交。
常听到的“GET 有长度限制”,限制其实来自浏览器和服务器对 URL 长度的限制,规范只建议至少支持 8000 字节的 URI。“POST 比 GET 安全”也不准确,POST 只是参数不出现在地址栏和服务器访问日志的 URL 里,抓包照样能看到,真正的保护要靠 HTTPS。
要注意,规范不禁止 GET 带请求体,但它没有约定的含义,有的服务器和代理会直接拒绝,所以不要这么用。用 GET 做删除这类修改操作也是错的,浏览器预取、爬虫访问链接都可能在用户不知情时触发它。
安全和幂等为什么重要
浏览器和中间设备会根据方法的语义做决定。因为 GET 是安全的,浏览器可以放心地预取链接,爬虫可以随便访问页面,网络出错时客户端可以自动重试。如果把“删除文章”做成 GET /delete?id=1,一次预取或爬虫访问就可能把文章删掉,CSRF 攻击也更容易,一张图片的 src 就能发出这个请求。
POST 不幂等,所以浏览器不会自动重发它。表单提交后刷新页面,浏览器会弹窗确认,就是怕重复提交。业务上要防止重复下单,常见做法是前端提交后禁用按钮,后端用一个唯一的请求 ID 去重。
各方法的安全性和幂等性见《HTTP 方法的安全性和幂等性是什么意思?》。
缓存上的区别
GET 的响应可以按 Cache-Control 等响应头缓存,同一个 URL 下次可能直接从缓存读取,见《强缓存与协商缓存如何配合?》。
POST 的响应在规范上也能缓存,但条件很苛刻:要带明确的过期信息,还要有和请求地址相同的 Content-Location。实际上浏览器和 CDN 几乎都不缓存 POST,所以需要缓存的查询接口应该用 GET。
常见追问
GET 请求会发两个 TCP 包,POST 会先发头再发体吗?
这不是 HTTP 规范规定的,而是某些客户端或服务器的实现细节,不能作为两者的区别。HTTP/2 和 HTTP/3 下请求本来就被拆成多个帧传输。
查询条件特别复杂,URL 放不下怎么办?
可以用 POST 发查询,但要知道代价:响应不能用普通的 HTTP 缓存,也没法分享链接。另一种做法是把查询条件保存到服务端,生成一个短 ID,再用 GET 带上这个 ID 查询。
PUT 和 POST 有什么区别?
PUT 是幂等的,表示“把这个资源设成我给的内容”,发多次结果一样,常用于整体更新;POST 表示“请处理这些数据”,常用于新建,发多次可能新建多条。