面试官问 GET 和 POST 的区别,千万别只说“参数位置不同” HTTP 请求方法与报文结构从协议规范到工程实践面试中GET 和 POST 有什么区别是一道几乎必考的题。大多数人能说出GET 参数在 URL、POST 参数在 Body这个表层差异但如果追问下去——GET 请求可以有 Body 吗POST 请求的参数能放在 URL 里吗HTTP 规范到底是怎么定义这两个方法的PUT 和 DELETE 呢RESTful 是谁规定的很多人就说不清了。更别提 HTTP/2 和 HTTP/3 对这些概念的实质性改变了。这篇笔记把 HTTP 请求方法和报文结构从 RFC 规范层面拆开再落到实际开发和排错的场景里。一、HTTP 请求方法的协议定义1.1 方法不是约定俗成是规范强制HTTP 请求方法的语义最早由 RFC 7231HTTP/1.1 语义和内容2014 年发布替代了 1999 年的 RFC 2616定义。2022 年IETF 发布了 RFC 9110HTTP Semantics将 HTTP/1.1、HTTP/2 和 HTTP/3 通用的核心语义方法、状态码、Header统一提取到一个文档中正式废弃了 RFC 7231。因此今天讨论 HTTP 方法语义时应以 RFC 9110 为准。规范给每个方法赋予了语义semantics也就是说方法不仅是一个字符串它对服务器和中间件的行为有约定效果。RFC 7231 定义的方法及其语义方法语义是否安全是否幂等是否有请求体GET获取资源的表示是是无规范不禁止但不预期有HEAD和 GET 一样但不返回消息体是是无OPTIONS获取目标资源的通信选项是是无POST在目标资源上处理数据否否有PUT用请求体替换目标资源的全部内容否是有DELETE删除目标资源否是无规范允许但不预期有TRACE沿着到目标资源的路径执行消息回环测试是是无CONNECT建立到目标资源的隧道否否无隧道建立后数据走全双工PATCH对资源进行部分修改否否有两个关键概念的精确定义安全方法Safe Method方法的语义不会对服务器上的资源产生副作用。GET、HEAD、OPTIONS、TRACE 是安全方法。这并不意味着 GET 请求不能修改数据——规范说的是方法的语义本身不应该产生副作用而不是实际实现不能。比如你写了一个GET /delete-all-users的接口这违反了 HTTP 语义但它能正常工作。幂等方法Idempotent Method同一个请求执行一次和执行多次对服务器上资源的状态影响相同。PUT 是幂等的把资源替换为指定内容执行 100 次结果一样POST 不是幂等的提交一次订单和提交 100 次订单效果完全不同PATCH 通常不是幂等的取决于具体实现。1.2 GET不只是查询GET 方法的规范定义是“获取某个资源的当前表示”。注意措辞——是获取不是查询数据库。GET 请求的响应应该是资源的表示representation通常是 HTML、JSON、XML 等格式。一个容易误解的点RFC 7231 并没有禁止 GET 请求携带请求体。规范原文写的是A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.意思是GET 请求可以有 Body但规范没有定义这个 Body 的语义有些服务器可能会直接忽略或拒绝它。cURL 和 Postman 允许在 GET 请求中携带 Body服务端框架通常不会去读取它。但浏览器的fetchAPI 严格遵守规范——如果你写fetch(url, { method: GET, body: data })浏览器会直接抛出TypeError: Request with GET/HEAD method cannot have body.。这个差异反映了不同 HTTP 客户端对规范的执行力度。GET 请求的参数放在 URL 里不是规范强制规定的——它是惯例convention。URL 里的查询字符串?keyvaluefoobar是 URI 规范的一部分和 HTTP 方法无关。你完全可以用GET /users?nameAlice来查询也可以用GET /users/Alice路径参数。但如果你想把大量参数传给 GET 请求放在 URL 里会遇到URL 长度限制的问题——这个限制不是 HTTP 规范定义的而是浏览器和 Web 服务器各自设定的。Chrome 对 URL 的长度限制是 2MB但 Nginx 默认的large_client_header_buffers配置只接受 4K-8K 的 URL。IE 曾经更极端限制在 2048 字节。1.3 POST不只是提交POST 的规范定义是“根据请求体中的数据来处理目标资源”。注意——POST 的语义比大多数人想象的要宽泛得多。RFC 7231 给出了 POST 的几个典型用途用 HTML 表单给数据处理过程提供一组数据比如搜索给公告板、新闻组、邮件列表或博客提交消息给数据处理过程提供一组数据块比如通过表单字段提交的数据通过追加操作扩展数据库POST 没有说必须把参数放在 Body 里——它说的是请求体中有数据。URL 里照样可以有查询参数。POST /articles?drafttrueBody 里放文章内容这是完全合法的 HTTP 请求。只不过在实际开发中POST 的参数通常放在 Body 里查询参数放在 URL 里这是一个工程惯例。1.4 PUT、DELETE、PATCH这三个方法经常被放在一起讨论但语义差异很大。PUT的语义是用请求体的内容替换目标资源的全部内容client-defined replacement。它的 URL 应该指向资源的完整标识。比如PUT /articles/42Body 里放的是第 42 篇文章的完整内容。如果你只传了 title 没传 content服务端应该把 content 设为 null而不是保留原来的值——这就是替换的含义。DELETE的语义是删除目标资源。DELETE /articles/42应该删除第 42 篇文章。RFC 7231 允许 DELETE 请求携带 Body但没有定义其语义——实际工程中几乎没有人这么做。PATCH的语义是对资源进行部分修改。和 PUT 的全部替换不同PATCH 只修改你传了的部分。Body 的格式由Content-Type头指定——通常是application/merge-patchjsonRFC 7396或application/json-patchjsonRFC 6902。// PUT /articles/42 的请求体——完整的文章{title:新标题,content:新内容,published:true}// PATCH /articles/42 的请求体——只改标题{title:只改标题}PUT 是幂等的执行 100 次结果一样PATCH 通常不是取决于 patch 的具体内容。1.5 RESTful 是谁规定的很多人把 REST 和 HTTP 方法绑定在一起以为 REST 是某个标准。实际上RESTRepresentational State Transfer是 Roy Fielding 在 2000 年的博士论文里提出的一种架构风格architectural style它不是 W3C 标准不是 RFC也没有强制约束力。REST 描述的是一种分布式超媒体系统的架构约束其中包括资源Resource通过 URI 标识资源的表示Representation通过 HTTP 方法操作使用统一接口Uniform Interface所谓RESTful API就是把 HTTP 方法当作操作语义来用GET 读、POST 创建、PUT 全量更新、DELETE 删除、PATCH 部分更新。但一个 API 用了 GET 来创建资源它也仍然是 HTTP API——只是不符合 RESTful 风格而已。HTTP 规范并不强制你把方法用对。二、GET 和 POST 的差异逐层分析面试中最常见的对比维度是参数位置、安全性、缓存、长度限制。但这些维度的背后有更深层的协议原理。2.1 参数位置的本质GET 的参数放在 URL 里POST 的参数放在 Body 里——这是惯例不是规范强制。RFC 7231 只规定了 GET 方法的语义是获取没有规定参数必须放哪。但这个惯例的形成有工程原因URL 是可以被浏览器记录在历史记录里的、可以被收藏夹保存、可以被日志服务器写进 access log。如果敏感参数如 token、密码放在 URL 里它们会被这些渠道暴露。这是GET 不安全的真正含义——不是传输层不安全HTTPS 下都是加密的而是信息泄露渠道太多。Body 的内容不会出现在 URL、浏览器历史记录和 access log 里通常只记录 Content-Length 而不记录 Body 内容相对更不容易泄露。2.2 GET 不安全的安全模型很多人说POST 比 GET 安全这句话的前提是 HTTPS。在 HTTP明文传输下GET 和 POST 的参数都可以被中间人抓包看到POST 并不比 GET 更安全——只是 POST 的参数在 URL 里看不到在 Body 里一样能被截获。在 HTTPS 下整个 HTTP 报文包括 URL、Header、Body都被 TLS 加密中间人看不到任何内容。但即便在 HTTPS 下GET 的参数仍然会出现在以下位置浏览器地址栏浏览器历史记录代理服务器的 access logHTTP Referer 头当你从一个页面跳转到另一个页面时Referer 头会包含来源页面的完整 URLNginx / Apache 的请求日志这就是为什么敏感操作登录、支付、修改密码不应该用 GET——不是因为 GET 的传输不安全而是因为 GET 的信息暴露面太广。2.3 缓存行为差异GET 请求默认是可以被缓存的。浏览器、CDN、反向代理都会根据Cache-Control和Expires响应头来缓存 GET 的响应。如果你发了一个 GET 请求CDN 可能直接返回缓存的响应而不经过后端服务器。POST 请求默认不被缓存。这是 RFC 7231 的规定Responses to POST requests are not cacheable by default.这个差异在实际工程中有实际影响。如果你用 GET 来执行一个创建操作比如GET /create-orderCDN 可能会缓存第一次的响应后续的相同请求直接返回缓存订单只创建了一次。这也是为什么 RESTful 风格要求创建操作用 POST。2.4 编码差异URL 中的查询参数需要 URL 编码percent-encoding空格变成%20或中文变成%E4%B8%AD%E6%96%87特殊字符逐个转义。Body 的内容取决于Content-Typeapplication/x-www-form-urlencoded格式和 URL 查询字符串一样需要 URL 编码multipart/form-data每个字段用 boundary 分隔适合文件上传和二进制数据不需要对整个 Body 做编码application/jsonBody 是 JSON 字符串UTF-8 编码2.5 一张完整的对比表维度GETPOSTRFC 语义获取资源表示处理目标资源参数位置惯例URL 查询字符串请求体Body是否有 Body规范不禁止但不预期有有安全方法是语义无副作用否幂等方法是否可缓存是默认否默认URL 长度限制受浏览器/服务器限制无Body 大小不受 URL 限制编码URL 编码取决于 Content-Type信息暴露面URL、历史记录、日志、RefererBody通常不出现在日志中典型用途查询、获取页面提交表单、创建资源、上传文件三、HTTP 报文结构3.1 一个完整的 HTTP 请求报文HTTP 请求报文由四部分组成POST /api/articles HTTP/1.1 ← 请求行Request Line Host: api.example.com ← Content-Type: application/json ← 请求头Headers Authorization: Bearer eyJhbGciOi... ← Content-Length: 38 ← Accept: application/json ← User-Agent: Mozilla/5.0... ← ← 空行CRLF {title: Hello, content: World} ← 请求体Body请求行包含三个部分方法POST、请求目标/api/articles、HTTP 版本HTTP/1.1用空格分隔。请求头是一个或多个键值对每行一个格式为Header-Name: value。Header 名不区分大小写RFC 7230 规定值区分大小写。请求头和请求体之间必须有一个空行CRLF即\r\n\r\n。3.2 请求头Header传输元数据请求头的作用是携带请求的元信息——告诉服务器我是什么、我要什么、我发的是什么格式的数据。按照 RFC 7230 和 RFC 7231 的分类请求头大致可以分为几类内容协商类Accept: application/json ← 期望的响应格式 Accept-Language: zh-CN,zh;q0.9,en;q0.8 ← 期望的语言 Accept-Encoding: gzip, deflate, br ← 支持的压缩格式 Accept-Charset: utf-8 ← 支持的字符集q是权重值quality factor取值 0-1表示偏好程度。zh-CN,zh;q0.9,en;q0.8的意思是最偏好简体中文其次其他中文变体权重 0.9最后英语权重 0.8。内容描述类Content-Type: application/json ← 请求体的数据格式 Content-Length: 38 ← 请求体的字节长度 Content-Encoding: gzip ← 请求体的压缩方式 Content-Disposition: form-data; namefile ← multipart 中标识字段Content-Type是请求头中最容易踩坑的一个。它的值决定了服务器如何解析 Bodyapplication/x-www-form-urlencoded键值对用分隔用连接值需要 URL 编码。这是 HTML 表单默认的提交格式multipart/form-data用 boundary 分隔的多部分数据。每个部分有自己的 Content-Type。这是文件上传的必须格式application/jsonBody 是 JSON 字符串。现代 API 的主流格式text/xml或application/xmlBody 是 XML。SOAP 协议使用这种格式application/octet-stream原始二进制流。通常用于文件下载认证类Authorization: Bearer eyJhbGciOiJIUzI1Ni... ← JWT Token Cookie: session_idabc123 ← Cookie 认证 X-API-Key: your-api-key-here ← 自定义 API Key客户端信息类User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ← 浏览器/客户端标识 Referer: https://example.com/articles ← 来源页面 Origin: https://example.com ← 请求来源跨域请求时浏览器自动加 X-Forwarded-For: 203.0.113.50 ← 代理链中的客户端真实 IP X-Request-ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890 ← 请求追踪 ID注意Referer和Origin的区别Referer是完整的来源 URL包括路径Origin只有协议域名端口。两者都在跨域请求中被浏览器自动添加但用途不同——CORS 用Origin做来源判定Referer用于统计和日志分析。缓存控制类If-None-Match: etag-value ← 条件请求如果 ETag 没变返回 304 If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT ← 条件请求如果未修改返回 304 Cache-Control: no-cache, no-store ← 客户端要求不缓存3.3 请求体Body传输实际数据请求体只在部分 HTTP 方法中才有实际意义。GET、HEAD、DELETE、OPTIONS 通常没有 Body虽然规范不禁止。POST、PUT、PATCH 通常携带 Body。请求体的格式由Content-Type头决定。这里有一个需要特别注意的地方请求体的长度必须和Content-Length头一致或者使用Transfer-Encoding: chunked进行分块传输。如果Content-Length声明的长度和实际 Body 长度不一致服务器会报错或拒绝请求。在 HTTP/1.1 中如果没有Content-Length也没有Transfer-Encoding: chunked服务器不知道 Body 在哪里结束因为 TCP 是流式的没有消息边界可能导致超时或行为不确定。大多数 HTTP 客户端库会自动处理这个问题但在手动构造原始 HTTP 请求时需要特别注意。3.4 分块传输编码Chunked Transfer Encoding当响应内容无法提前确定长度时比如动态生成的内容可以使用分块传输HTTP/1.1 200 OK Transfer-Encoding: chunked Content-Type: application/json 1a\r\n ← 十六进制长度26 字节 {articles: [\r\n 30\r\n ← 十六进制长度48 字节 {id: 1, title: Hello},\r\n 30\r\n ← 十六进制长度48 字节 {id: 2, title: World}\r\n 2\r\n ← 十六进制长度2 字节 ]}\r\n 0\r\n ← 结束标记 \r\n每个 chunk 以十六进制表示的数据长度开头后跟 CRLF然后是数据本身再跟 CRLF。最后一个 chunk 的长度为 0表示传输结束。3.5 多部分表单Multipart Form Data文件上传时使用的multipart/form-data格式POST /upload HTTP/1.1 Content-Type: multipart/form-data; boundary----WebKitFormBoundary7MA4YWxkTrZu0gW ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; nametitle Hello Article ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; namefile; filenamephoto.jpg Content-Type: image/jpeg (二进制文件数据...) ------WebKitFormBoundary7MA4YWxkTrZu0gW--boundary是一个自定义的分隔符用--开头和结尾标记每个部分的边界。最后一行的--后面没有 boundary表示结束。每个部分可以有自己的Content-Type和Content-Disposition。四、HTTP 状态码不只是 200 和 4044.1 状态码的结构状态码是一个三位整数第一位数字定义了响应的类别1xxInformational信息性响应表示请求已被接收继续处理2xxSuccess请求已成功被服务器接收、理解、并接受3xxRedirection需要客户端采取进一步的操作才能完成请求4xxClient Error客户端提交了有问题的请求5xxServer Error服务器在处理请求时出现了错误4.2 每个类别中最常用的状态码2xx 成功状态码含义典型场景200 OK请求成功GET 返回资源、POST 返回处理结果201 Created资源创建成功POST 创建新资源后返回204 No Content成功处理无响应体DELETE 成功删除资源201 在 RESTful API 中特别重要。当客户端 POST 创建了一个资源服务器应该返回 201 而不是 200同时在响应的Location头中给出新资源的 URI。HTTP/1.1 201 Created Location: /api/articles/42 Content-Type: application/json {id: 42, title: Hello, content: World}3xx 重定向状态码含义典型场景301 Moved Permanently永久重定向域名迁移、HTTP → HTTPS302 Found临时重定向维护页面跳转、登录后重定向304 Not Modified资源未修改条件请求浏览器缓存有效服务端告知用缓存307 Temporary Redirect临时重定向保持方法不变POST 提交后的临时跳转301 和 302 有一个容易混淆的区别301 会把后续的 GET 请求也重定向到新地址搜索引擎会更新索引302 只重定向当前这一次。另外302 在规范中允许浏览器把后续请求的方法改为 GET即便原始请求是 POST307 不允许——它强制保持原始方法不变。4xx 客户端错误状态码含义典型场景400 Bad Request请求语法错误JSON 格式不合法、必填参数缺失401 Unauthorized未认证Token 过期、未登录403 Forbidden无权限已认证但无权访问该资源404 Not Found资源不存在URL 错误、资源已被删除405 Method Not Allowed方法不被允许用 GET 访问只支持 POST 的接口408 Request Timeout请求超时客户端发送请求太慢409 Conflict请求冲突并发修改、唯一约束冲突413 Payload Too Large请求体过大上传文件超过服务器限制415 Unsupported Media Type不支持的 Content-Type发送 XML 但服务器只接受 JSON422 Unprocessable Entity语义错误请求格式正确但语义无效FastAPI/Pydantic 数据验证失败429 Too Many Requests请求过于频繁触发了速率限制Rate Limiting401 和 403 的区别是高频面试题401 表示我不知道你是谁未认证403 表示我知道你是谁但你没权限已认证但无权。422 是 Web API 中非常有用的状态码。4xx 范围内400 表示请求格式错误比如 JSON 解析失败422 表示请求格式正确但语义不合法比如 JSON 能解析但某个字段类型不对或值不在允许范围内。FastAPI 用 422 来返回 Pydantic 验证失败的错误。5xx 服务端错误状态码含义典型场景500 Internal Server Error服务器内部错误未捕获的异常、代码 Bug502 Bad Gateway上游服务器返回了无效响应反向代理Nginx后端挂了503 Service Unavailable服务不可用服务器过载、维护中504 Gateway Timeout上游服务器响应超时后端处理时间过长网关等不及了502 和 504 的区别经常在 Nginx 反向代理场景中遇到502 是上游服务器没有响应或返回了无法解析的响应连接问题504 是上游服务器响应太慢超时。4.3 条件请求与状态码的配合HTTP 协议支持条件请求Conditional Request允许客户端在请求中携带验证信息如果资源没有变化服务器返回 304 Not Modified不发送响应体。这大幅减少了不必要的数据传输。两种主要的条件请求方式ETag实体标签方式# 第一次请求 GET /api/articles/42 HTTP/1.1 Host: api.example.com HTTP/1.1 200 OK ETag: abc123 Content-Type: application/json {id: 42, title: Hello} # 第二次请求带上 ETag GET /api/articles/42 HTTP/1.1 Host: api.example.com If-None-Match: abc123 HTTP/1.1 304 Not Modified 无响应体节省带宽Last-Modified 方式GET /api/articles/42 HTTP/1.1 If-Modified-Since: Wed, 21 Oct 2020 07:28:00 GMT HTTP/1.1 304 Not ModifiedCDN 和浏览器缓存广泛使用这种机制来减少回源请求。五、HTTPS 对报文结构的影响在 HTTPS 下整个 HTTP 报文请求行、请求头、请求体都被 TLS 加密。TLS 的加密层次是HTTP 报文明文 → TLS 加密层对称加密如 AES-256-GCM → TCP 层 → IP 层中间人ISP、Wi-Fi 热点运营者、代理服务器只能看到 TCP 连接的目标 IP 和端口以及 TLS 握手的证书信息无法看到 HTTP 报文的内容。但 HTTPS 不保护以下信息SNIServer Name IndicationTLS 握手时以明文发送的目标域名。用于多域名虚拟主机的路由请求的 URL 路径和查询参数如果使用 HTTP/2 和 ECHEncrypted Client HelloSNI 也可以加密但 URL 路径在 TLS 层已经是加密的了域名本身通过 DNS 查询仍然可以看到你访问了哪个域名这就是为什么即使使用了 HTTPS敏感参数仍然不应该放在 URL 的查询字符串里——URL 可能被浏览器历史记录、Referer 头、服务器日志等渠道泄露这些渠道在 TLS 加密保护的范围之外。六、HTTP/2 和 HTTP/3 对请求方法与报文结构的影响6.1 HTTP/2二进制分帧HTTP/2RFC 75402015 年发布在应用层语义上与 HTTP/1.1 完全兼容——GET 仍然是 GETPOST 仍然是 POST状态码的含义不变。但传输层的实现方式完全不同。HTTP/1.1 的报文是纯文本的一行一行用 CRLF 分隔。HTTP/2 把报文拆成了帧Frame放在流Stream里传输。每个帧有类型HEADERS、DATA、SETTINGS 等、长度、流 ID、标志位。对请求方法和报文结构的影响请求头压缩HPACKHTTP/2 用 HPACK 算法压缩请求头对于大量重复的 Header如 Cookie、User-Agent压缩率非常高。这意味着 GET 请求的长 URL 查询字符串虽然在 Header:path伪头字段里但经过 HPACK 压缩后实际传输的字节数比 HTTP/1.1 少很多多路复用HTTP/2 允许在同一个 TCP 连接上并发多个请求/响应多个 Stream每个 Stream 可以有不同的方法。这消除了 HTTP/1.1 的队头阻塞Head-of-Line Blocking问题——一个慢的请求不会阻塞其他请求请求体仍然是 DATA 帧HTTP/2 的请求体和响应体通过 DATA 帧传输Content-Length头变为可选如果不提供用END_STREAM标志标识数据结束6.2 HTTP/3基于 QUIC 的传输HTTP/3RFC 91142022 年发布把传输层从 TCP 换成了 QUIC基于 UDP。这对 HTTP 方法语义没有影响但对连接管理和性能有实质改变0-RTT 连接建立在之前的 TLS 会话基础上HTTP/3 可以在握手阶段就发送请求不需要像 TCP TLS 那样等 1-2 个 RTT解决 TCP 层的队头阻塞HTTP/2 虽然在应用层解决了队头阻塞但 TCP 层仍然存在——一个 TCP 包丢失会阻塞该连接上所有 Stream 的数据。QUIC 为每个 Stream 独立维护拥塞控制和重传一个 Stream 的丢包不影响其他 Stream头部压缩从 HPACK 换为 QPACKHTTP/2 的 HPACK 压缩算法依赖动态字典多个 Stream 共享同一个连接的状态。如果在 QUIC基于 UDP上直接使用 HPACK一个 UDP 包的丢失会导致后续 Stream 的头部解压阻塞——因为解压状态依赖于前面已收到的包。HTTP/3 因此引入了 QPACK它将编码器和解码器的动态表同步分离到单独的请求-响应流中使得单个 Stream 的丢包不再阻塞其他 Stream 的头部解压。6.3 WebDAV 扩展方法HTTP 协议允许扩展方法Extension Methods。WebDAVRFC 4918定义了一组用于文件管理的方法PROPFIND、PROPPATCH、MKCOL、COPY、MOVE、LOCK、UNLOCK。这些方法不在 RFC 7231 的标准方法列表里但它们是合法的 HTTP 方法广泛用于 Web 文件管理如 Nextcloud、ownCloud。七、工程实践中的排错技巧7.1 用 curl 构造原始请求curl是排查 HTTP 问题的利器。几个常用技巧# 只看响应头不看响应体curl-s-o/dev/null-D- https://api.example.com/articles# 查看 TLS 握手信息SNI、证书curl-vhttps://api.example.com/21|grep-ESSL|TLS|subject|issuer# 发送 POST 请求并指定 Content-Typecurl-XPOST https://api.example.com/articles\-HContent-Type: application/json\-HAuthorization: Bearer your-token\-d{title: Hello, content: World}# 查看 301/302 重定向的完整链路curl-v-Lhttps://example.com21|grep-ELocation|GET|Host7.2 浏览器 DevTools 中的报文查看Chrome DevTools 的 Network 面板可以查看每个请求的完整报文Headers 标签查看请求行、请求头、响应头。勾选Preserve log可以在页面跳转后保留之前的请求记录Payload 标签查看请求体的解析后内容如果是表单或 JSONPreview / Response 标签查看响应体的内容Timing 标签查看请求的各个阶段耗时DNS 查找、TCP 连接、TLS 握手、请求发送、服务器处理、内容下载7.3 常见错误模式415 Unsupported Media Type通常是客户端发了 JSON 格式的 Body但没有设置Content-Type: application/json。服务器不知道怎么解析 Body返回 415400 Bad Request “JSON parse error”JSON 格式有误比如多了个逗号、用了单引号而不是双引号、键没有用双引号括起来413 Payload Too Large上传文件超过 Nginx 的client_max_body_size或后端框架的限制408 Request Timeout客户端建立连接后发送数据太慢通常出现在大文件上传时网络不稳定八、总结HTTP 请求方法和报文结构不是约定俗成的经验之谈而是 RFC 规范精确定义的协议语义。GET 的安全和幂等是规范赋予的语义属性不是技术上的安全保障——真正的安全性来自 HTTPS 正确的参数传递方式。请求头携带元数据、请求体携带实际数据、状态码反馈处理结果这三层构成了 HTTP 通信的基本骨架。在工程实践中理解这些协议细节的价值主要体现在排错能力上——当你看到 415 错误时能立刻想到 Content-Type 的问题看到 422 能联想到请求体格式正确但语义不合法看到 502 vs 504 能区分是后端挂了还是后端太慢。这些判断力来自对协议规范的底层理解而不是死记硬背状态码表。