ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

HTTP/HTTPS协议全解析:请求头、响应头与状态码实战排查

HTTP/HTTPS协议全解析:请求头、响应头与状态码实战排查 如果说HTTP协议是互联网世界的快递物流体系那请求头、响应头和状态码就是贴在包裹上的面单与签收回执数据包结构则是货物怎么打包、车辆怎么跑的底层规则。很多刚接触后端的同学会用curl调接口会看浏览器F12里的Network面板但一旦遇到“为什么请求头要带这个字段”“为什么返回502”“为什么HTTPS抓包全是密文”这类问题就容易被卡住。这篇东西我就把HTTP/HTTPS从报文格式、常用头字段、状态码语义到抓包排错的完整链路串一遍结合我这些年实际踩过的坑尽量讲得接地气一点。这篇文章适合谁后端开发、前端调试、运维排查、做爬虫或安全测试的朋友还有刚学网络基础的学生。读完你至少能把浏览器里那一堆请求头、响应头看懂七七八八也能独立排查大部分HTTP层面的故障。1. 先搞清楚HTTP和HTTPS到底在解决什么问题1.1 从一次网页访问说起你打开一个网页输入地址按下回车背后发生了很多事DNS把域名解析成IP浏览器和服务器建立TCP连接然后浏览器按照HTTP协议格式往这个TCP连接里写入一段文本这段文本就叫HTTP请求。服务器读完之后按照同样的协议格式返回一段文本这就是HTTP响应。浏览器拿到响应再根据里面的HTML、CSS、JS去渲染页面。这里的核心是“约定”。HTTP就是一个约定好的对话格式规定了“你该怎么说、我该怎么答”。它本身不关心传输细节TCP负责可靠传输HTTP只负责把语义表达清楚。所以你会看到HTTP报文其实是非常简单的纯文本按行排列人眼能直接读懂。这也是HTTP至今没有被取代的根本原因——简单、通用、易于调试。但HTTP有一个致命问题内容是明文。网络链路上任何一个能抓包的人都能完整看到你发送的用户名、密码、Cookie。这就是为什么后来有了HTTPS。HTTPS不是一个新的应用层协议它本质上是HTTP over TLS也就是在HTTP外面套了一层加密通道。数据在发送前先被加密接收后再解密这样即使报文被截获看到的也只是密文。1.2 HTTPS多做了哪些事HTTPS比HTTP多做的最关键一件事是TLS握手。TLS握手过程大致分这么几步客户端先发一个ClientHello告诉服务器自己支持的TLS版本、加密套件列表。服务器从中选出一套双方都支持的方案回一个ServerHello同时把自己的证书发给客户端。客户端验证证书是否可信验证通过后双方通过密钥交换算法比如ECDHE协商出一个会话密钥。之后所有HTTP报文都用这个会话密钥加密传输。这一步里有个概念特别重要证书。证书的作用是让客户端确认“服务器确实是它声称的那个服务器”防止有人冒充。浏览器有一个内置的信任列表证书只有由列表中信任的CA签发才被认为是合法的。所以很多内网自签名证书会在浏览器里报“不安全”因为客户端不信任这个签发者。我在实际项目里见过不少HTTPS配置问题最常见的是证书链不完整。比如只配置了域名证书没有把中间证书一并配置结果某些客户端校验失败而浏览器却能打开。这是因为浏览器有自动补齐中间证书的功能但很多自研客户端、curl、手机App没有。排查方法很简单用openssl s_client去连一下服务端看看证书链是否完整。1.3 哪些场景还在用HTTP你可能会问现在都2025年了谁还在用HTTP答案是比你想象的多得多。开发调试阶段本地接口基本都用HTTP方便抓包看明文。内网服务之间通信很多系统也懒得上HTTPS因为内部网络默认安全。还有嵌入式设备领域比如ESP01S、STM32这类资源受限的硬件跑一个完整的TLS握手可能需要几百KB的内存和额外的时间很多时候就直接用HTTP。C写的QT局域网应用、树莓派上的小服务也经常是HTTP。但只要是公网、涉及用户敏感信息的服务或者会被搜索引擎收录的页面都应该上HTTPS。浏览器对HTTP页面会有“不安全”标识搜索引擎也可能对HTTPS页面有排名权重。所以我的建议是公网一律HTTPS内网自行评估开发环境随意但上线前必须检查。2. 数据包结构HTTP报文到底长什么样2.1 HTTP报文的四个组成部分一个标准HTTP报文由四部分组成起始行、头部字段、空行、正文。很多新手会忽略那个空行但它是必须的。空行用CRLF回车换行表示作用是区分“头部”和“正文”。如果服务端解析报文时没找到空行就会认为头部还没结束一直等待直到超时。举个例子一个最简单的GET请求报文长这样GET /index.html HTTP/1.1 Host: example.com User-Agent: Mozilla/5.0 Accept: */* Connection: close注意最后有一个空行。这个请求没有正文所以空行之后就是结束。如果发送端忘了这个空行接收端可能解析失败卡在那里。正文部分不是每个请求都有。比如GET请求一般没有正文POST、PUT请求通常有。正文和头部的分隔就是那个空行。2.2 请求报文结构拆解请求报文的第一行叫请求行格式是方法 路径 协议版本比如POST /api/login HTTP/1.1这里的方法是POST路径是/api/login协议版本是HTTP/1.1。协议版本决定了报文格式的细微差异HTTP/2之后报文不再是纯文本而是二进制帧结构但头部字段的语义仍然沿用。接下来是请求头一行一个字段格式是“字段名: 字段值”。比如Host: api.example.com Content-Type: application/json Authorization: Bearer eyJhbGciOi... Content-Length: 37最后是空行和请求正文比如JSON字符串{username:admin,password:123456}这里有一个容易踩坑的点如果写了Content-Length那么它的值必须和实际发送的body字节数完全一致。不一致的话服务端要么读取不完要么多读导致连接错乱。所以自己拼接HTTP报文时Content-Length一定要用实际字节数不是字符数中文尤其要注意。2.3 响应报文结构拆解响应报文的结构和请求报文基本对称区别在第一行。响应第一行叫状态行格式是协议版本 状态码 状态描述比如HTTP/1.1 200 OK接下来是响应头同样是一行一个字段。然后是空行最后是响应正文。比如HTTP/1.1 200 OK Content-Type: text/html; charsetutf-8 Content-Length: 1234 Set-Cookie: sessionabc123; Path/ html.../html响应头里比较关键的有Content-Type它告诉客户端正文是什么类型Content-Length告诉客户端正文多长Set-Cookie让浏览器种下Cookie。这些字段我会在第三节详细讲。2.4 从TCP视角看HTTP与HTTPS数据包如果你想在数据包层面看HTTP最好的工具是Wireshark。HTTP是明文协议Wireshark可以直接把应用层内容解析出来你甚至能看到请求行、每个头部字段。你可以观察到一次HTTP请求先经历TCP三次握手然后客户端发送应用层数据服务器回ACK再发送响应数据。但HTTPS在Wireshark里就不一样了。你只能看到一个TCP流里面是TLS记录每个记录有一个5字节的头部标明类型、版本和长度后面是加密数据。你无法直接看到HTTP内容。想看到HTTPS里的明文HTTP有一个官方且合规的调试方法设置SSLKEYLOGFILE环境变量。Chrome、Firefox、curl这些支持NSS加密库的客户端都会在SSLKEYLOGFILE指定的文件里写入会话密钥。把这个文件路径填到Wireshark的TLS协议设置里Wireshark就能用这些密钥解密TLS流量还原出HTTPS里的HTTP报文。这个技巧在排查HTTPS接口超时、响应内容异常时特别好用。我遇到过一次前端说接口返回了错误JSON后端说没收到请求最后就是靠SSLKEYLOGFILE解密本地流量发现请求根本没到达应用层而是被中间的网络设备拦截了。当然这个调试方法只适用于你能控制密钥的客户端不是你自己的客户端流量是解不开的。3. 请求头与响应头常用字段逐个说清3.1 请求头里的常客请求头是客户端告诉服务器“我是谁、我想要什么、我的能力是什么”的一组元信息。我用得最多的几个字段如下Host是必带的指定目标主机名和端口。在HTTP/1.1协议里这是必须字段没有Host服务器没办法做虚拟主机路由。User-Agent标识客户端类型比如浏览器版本、爬虫工具、手机App。很多服务器会用它做简单的反爬判断。我自己写爬虫的时候都习惯把User-Agent设置成浏览器一模一样的值不然容易被识别。但要注意有些安全策略会校验User-Agent是不是正常的浏览器标识如果你用库默认值去请求会直接返回403。Accept声明客户端能接受的媒体类型。Accept: application/json表示希望返回JSON。Accept-Encoding声明支持的压缩算法比如gzip、br。响应头里Content-Encoding会对应压缩方式。这里有个坑如果请求头设了Accept-Encoding: gzip但你自己写HTTP客户端时没做解压处理拿到的body就会是乱码的压缩数据。所以自己实现客户端时要么不发送这个头要么记得解压。Content-Type和Content-Length在POST/PUT请求里特别关键。Content-Type告诉服务器正文格式常见的有application/x-www-form-urlencoded、multipart/form-data、application/json。注意multipart/form-data上传文件时Content-Type字段会带一个boundary边界字符串正文里用这个字符串分块格式复杂建议直接用成熟库不要手拼。Authorization和Cookie是两种最常见的认证方式。Authorization一般配合Bearer Token或者Basic认证Cookie则是由服务器Set-Cookie后浏览器自动携带。调试接口时很多人会忘了带某个Cookie导致401这种问题看Response头里的WWW-Authenticate往往能看到提示。Referer和Origin表示请求来源。Referer是完整来源URLOrigin是来源站点的源信息主要用于跨域校验。有些安全接口会校验Referer白名单防止跨站请求伪造。我在CTF题目里经常看到伪造Referer绕过校验的情况原理就是服务器只检查这个字段不检查实际来源。3.2 响应头里的重要信息响应头是服务器告诉客户端“如何处理响应”的元信息。Content-Type的重要性仅次于状态码如果类型不对客户端解析会出错。比如一个接口返回JSON但Content-Type写成了text/htmlaxios这类库可能不会自动解析JSON导致你拿到的是一堆字符串。Content-Length表示响应体长度。如果服务器没正确设置这个值或者用了Transfer-Encoding: chunked分块传输客户端就得靠解析块长度来读完整个body。chunked格式在调试时看起来比较费劲但原理不难每个块以十六进制长度开头接着是数据最后是0长度块表示结束。Cache-Control是浏览器和CDN缓存策略的核心。常见的值有no-store、no-cache、max-age3600等。no-store表示绝不缓存适合敏感数据no-cache表示使用前必须先和服务器验证max-age表示在指定秒数内可以直接用缓存。排查“为什么页面不更新”或“为什么接口一直打源站”时第一时间看这个字段。Set-Cookie就是服务器种Cookie的指令可以带Path、Domain、HttpOnly、Secure、SameSite等属性。HttpOnly表示浏览器JS无法读取这个Cookie降低XSS风险Secure表示只能通过HTTPS传SameSite表示跨站时是否携带。如果登录状态一直掉看看是不是SameSite设置太严格。Location用于3xx重定向响应告诉客户端新的地址。浏览器收到302后会自动跳到Location指定的URL。如果重定向不生效看看响应头里有没有Location以及是不是被前端拦截了。Access-Control-Allow-Origin是CORS跨域的核心响应头。如果服务端不返回这个字段浏览器的同源策略会阻止前端读取响应。开发中常见的“CORS error”基本都是这个头没配好。注意它只能有一个值要么是具体域名要么是*不能配多个域名数组。安全相关的头也值得注意X-Frame-Options控制页面是否允许被iframe嵌入Content-Security-PolicyCSP限制资源加载来源Strict-Transport-SecurityHSTS强制浏览器只能走HTTPS访问。前两个是防点击劫持和XSS的利器HSTS对提升安全性帮助很大。3.3 自定义头与常见坑除了标准头你可以在请求和响应里自定义字段一般以X-开头比如X-Request-Id、X-Auth-Token。自定义头很方便但有几个坑一是某些服务器网关或反向代理会丢弃非标准头所以自定义头里的字段名尽量只用字母、数字、连字符不要用下划线。很多老一代服务器软件会把下划线开头的头忽略导致后端拿不到。我见过用X-Api_Key做认证结果Nginx默认过滤掉下划线头害得排查了半天。二是千万不要在自定义头里放敏感信息。头部虽然不能像URL一样被记录在访问日志里但很多反向代理、负载均衡器会把完整请求头打到日志里。一旦Token泄露后果很严重。三是跨域请求的自定义头会触发CORS预检。如果前端要带自定义头请求浏览器会先发一个OPTIONS请求服务端需要正确回应Access-Control-Allow-Headers否则正式请求不会发出。所以后端接了自定义头一定要把这个头名加入CORS白名单。3.4 请求头带Token的实际写法经常有人问a标签下载视频请求头怎么带token直接给a标签的href赋值一个下载URL浏览器会发起一个普通GET请求不会带上你指定的Authorization头。所以如果下载接口要求鉴权直接点a标签下载大概率会收到401或者302到登录页。正确做法是用fetch或XMLHttpRequest先发起带Token的请求拿到文件内容后用Blob生成一个本地URL再触发下载。示例代码如下fetch(/api/file/download, { headers: { Authorization: Bearer token } }) .then(res { if (!res.ok) throw new Error(HTTP res.status); return res.blob(); }) .then(blob { const url URL.createObjectURL(blob); const a document.createElement(a); a.href url; a.download filename.ext; document.body.appendChild(a); a.click(); URL.revokeObjectURL(url); });这里有个前提如果接口在另一个域名就要考虑CORS服务端必须允许前端携带Authorization头。还有如果文件很大把整个文件读进内存再创建Blob会比较吃内存更适合用流式下载保存到文件但浏览器端的下载能力受限大文件建议用分片或转交后端跳转。4. 状态码一张表看懂服务器想说什么4.1 1xx和2xx继续和成功1xx是信息响应很少见主要用于HTTP/1.1的100 Continue流程。客户端可以先发大头服务器回100后客户端再发body避免大body浪费流量。实际前后端开发中这个状态码一般不会直接暴露。2xx是成功类。200 OK最常见表示请求成功。201 Created表示资源创建成功通常在POST接口返回。204 No Content表示成功但没有响应体适合删除操作。206 Partial Content表示部分内容是断点续传、视频拖拽播放的核心。你在视频网站拖进度条时浏览器发一个Range请求头服务器返回206和指定字节段。如果服务器不支持Range直接返回200全量数据那视频拖动就会卡。4.2 3xx重定向3xx是重定向类告诉客户端“你要的东西不在这去那吧”。301 Moved Permanently是永久重定向常用于域名迁移、HTTP跳HTTPS旧地址会记录到浏览器所以修改后要谨慎。302 Found是临时重定向表示这次先转过去下次还来访问原地址。303 See Other常出现在POST之后告诉客户端去GET一个结果页。307和308是HTTP/1.1新增的和302、301语义类似但有一个关键区别重定向时保留请求方法和body。所以表单提交后的重定向选307会比302更安全避免POST变GET导致数据丢失。304 Not Modified是个特例它和重定向无关而是缓存协商的结果。客户端发送If-None-Match或If-Modified-Since服务器判断资源没变就返回304不带body。浏览器收到304后会用本地缓存。调试“为什么接口又走源站了”“为什么页面更新不了”时看304和Cache-Control很有用。4.3 4xx客户端错误4xx表示客户端发出的请求有问题。400 Bad Request是最笼统的错误通常是请求体格式错误、参数缺失、JSON解析失败。排查400先看接口文档再看Content-Type再看body是不是合法JSON。401 Unauthorized表示未认证即没有登录或Token无效。403 Forbidden表示认证了但没权限也可能是服务器主动拒绝比如IP被封、UA被拉黑、防盗链。403和401的区别要记住401是“你是谁”403是“你不够格”。404 Not Found是最常见的错误但原因很多URL路径写错、接口未部署、路由没匹配、服务器刻意隐藏资源。有一次我排查一个“接口404”发现是Nginx把带.的路径当静态文件处理了。还有次是网关把前缀剥掉了一层导致后端路由匹配不上前端看URL是对的后端日志里却是另一个路径。405 Method Not Allowed表示请求方法不被支持比如接口只允许GET你却发了POST。408 Request Timeout表示请求超时通常是客户端迟迟没把请求头发完。409 Conflict表示资源冲突比如创建了重复数据。413 Payload Too Large表示请求体过大常在文件上传场景出现要检查Nginx的client_max_body_size。415 Unsupported Media Type表示Content-Type不支持后端只吃JSON你发了form表单就会出现。429 Too Many Requests表示请求频率过高触发了限流。现在很多网关默认带防刷策略如果爬虫或测试脚本短时间内并发过大就会遇到。看响应头里有没有Retry-After那个是服务器建议你等多久。4.4 5xx服务端错误5xx表示服务器自己出问题了。500 Internal Server Error是最常见的服务端异常可能是代码抛了未捕获的异常、数据库连接失败、配置文件错误。502 Bad Gateway表示网关或反向代理没法从上游拿到有效响应。这里“上游”就是后端实际处理请求的服务。常见原因有后端服务崩了、端口写错、后端进程卡死、超时时间太短被网关熔断。504 Gateway Timeout表示网关等待上游响应超时。如果一个接口正常耗时需要20秒但网关默认超时15秒就会504。解决办法是优化接口耗时或调大网关超时。523 Origin Unreachable、524 A Timeout Occurred这类来自CDN厂商的状态码在排查时也要认识通常意味着源站挂了或源站响应太慢。502和504的排查思路比较固定先确认上游服务进程是否活着看端口是否监听再看后端日志有没有异常输出然后看负载均衡或网关的超时配置最后用curl直接访问上游IP测试绕开网关层缩小范围。我多次遇到502都是后端服务OOM被守护进程杀掉了看起来像网关问题实际上根因在应用侧。4.5 真实报错里的状态码聊几个我最近在处理接口报错时看到的例子。一个是调用某个大模型API时返回400原因是代码里把“thinking模式下必须回传的reasoning_content参数漏掉了”。这种400非常典型属于“请求体不符合上游API约束”。另一个是安装Python包时conda报403 Forbidden提示某个channel不可用。这个不是你的问题而是软件源那边限制了访问。排查时先看请求URL是不是官方源再考虑换成国内镜像源。这里提醒一下改软件源时要注意来源是否可信别随便用不明渠道的镜像。还有一次是请求一个外部接口一直404但浏览器打开URL没问题。最后发现是请求头里Host字段和实际服务端虚拟主机对不上。这再次说明状态码只是起点要结合请求头、响应头、服务端日志综合判断。5. 实操抓包、改包与调试实战5.1 curl是最好用的HTTP调试工具排查HTTP问题我第一工具永远是curl。它能看到请求和响应的完整原始报文。最常用的是-v参数会输出请求行、请求头、响应行、响应头以及TLS握手信息。curl -v https://api.example.com/users/1想只看响应头用-I参数发起HEAD请求curl -I https://api.example.com想自定义请求头用-Hcurl -X POST https://api.example.com/login \ -H Content-Type: application/json \ -H Authorization: Bearer test-token \ -d {username:admin,password:123456}如果服务端用的是自签名证书开发调试时可以加-k跳过证书校验但生产环境绝对不要这样用。想要更细的耗时分布用-w参数curl -o /dev/null -s -w TCP连接:%{time_connect}s 首字节:%{time_starttransfer}s 总耗时:%{time_total}s\n https://api.example.com这个输出能帮你初步判断瓶颈在网络、DNS解析还是后端处理。5.2 用Burp Suite改请求头理解CTF中的HTTP头注入做安全测试、CTF题目Burp Suite是绕不开的工具。它的核心能力是拦截浏览器或App的流量让你在请求发出去之前修改或者在响应返回之前修改。比如CTF里常见的“需要来自某个内部地址的请求”你可以在拦截到请求后手动加一个X-Forwarded-For: 127.0.0.1或者把Referer改成要求的地址。服务器如果只校验这个头就会放行。还有一种HTTP头注入的玩法是在参数里塞入回车换行CRLF导致服务器在响应头里额外插入字段。比如一个重定向参数可控时注入一个自定义响应头可能触发XSS或绕过防护。这种题目考验的就是你对HTTP报文结构的理解——头部和正文靠空行分隔如果用户输入被拼接到响应头里又没有过滤CRLF就可能打破结构。用Burp Suite时有一个常见坑改完请求头发送后发现服务器返回400很可能是你手动改的字段值格式不对比如少了冒号后面的空格。HTTP头部要求字段名和值之间用冒号加空格分隔但很多解析器允许没有空格为了兼容最好按标准写。5.3 JMeter录制HTTPS脚本做性能测试JMeter是标配。但录制HTTPS脚本时很多人会卡在证书上。JMeter录制HTTPS请求时会给你本地生成一个CA证书你需要先把它导入到系统信任的根证书列表里然后再配置浏览器或手机信任这个证书否则HTTPS连接会失败。具体流程大致是打开JMeter的HTTP(S)测试脚本记录器设置端口启动之后把浏览器的本地流量转发到该端口让浏览器走JMeter提供的入口。这里不展开每一处设置但核心点有两个一是证书信任二是确保浏览器关闭了自带的安全拦截。录制完成后脚本里会有一堆带有动态参数的请求比如登录的token、时间戳。直接回放多半会失败因为参数已经过期。所以脚本录制后要做参数化处理从JSON响应或正则提取器里动态取值。这也是很多新手觉得JMeter脚本“录完跑不通”的原因。5.4 HTTP连接复用Keep-Alive和连接池HTTP/1.1有一个重要特性连接复用也就是Keep-Alive。一个TCP连接可以连续发送多个请求不用每次请求都重新握手。这样能显著减少延迟和系统资源开销。HTTP/2更进一步引入多路复用一个连接上可以同时交错传输多个请求的响应彻底解决了HTTP/1.1的队头阻塞。实际开发中如果你用Java的HttpClient或Go的net/http默认都有连接池。但连接池不是越大越好。连接数过多会占满服务器和客户端的文件描述符反而性能下降。Go的http.Transport有MaxIdleConnsPerHost参数Java的HttpClient也有连接池大小上限配置要根据并发量合理设置。反向代理层也要注意Keep-Alive。Nginx的upstream配置里有个keepalive指令表示每个worker进程和上游服务保持的空闲长连接数量。如果不配置Nginx会每次请求都新建TCP连接到上游高并发下延迟会高。配置了keepalive还得在location里设置proxy_http_version 1.1并清掉Connection头否则长连接不生效。5.5 嵌入式HTTP场景ESP01S、STM32、QT嵌入式设备一般内存小、CPU弱很多场景下仍然用HTTP明文通信。ESP01S这类WiFi模块通过AT指令发HTTP请求很简单但要注意返回内容过长时缓冲区不够。我之前用ESP01S请求一个JSON接口响应才几百字节模块却经常返回超时后来发现是AT指令读取模式的等待时间设置太短。STM32上要发HTTP请求通常会移植一个小型HTTP客户端库比如cJSON配合lwIP的socket接口自己拼报文。这时候最关键的是报文格式不能错尤其是请求行结尾、头部空行、Content-Length。我写过一版在开发板上死活收不到响应最后用USB转串口把原始数据打出来发现是少了Host头协议栈直接忽略了请求。C的QT写HTTP服务器更适合局域网工具类应用。QTcpServer监听端口收到数据后按HTTP格式解析请求再拼响应返回。这个实现不复杂但一定要处理半包和粘包也就是一次read可能只收到半个请求或者一个包里有多个请求。做法是把数据缓存在buffer里每次先查找\r\n\r\n判断头部是否完整再用Content-Length判断body是否完整。这个思路在任何用TCP socket手写HTTP解析的地方都通用。6. 常见问题速查与避坑经验6.1 常见问题对照表现象可能原因优先检查点请求返回400body格式错、Content-Type不对、缺少必需参数请求头Content-Type、body原始内容每次刷新页面都走源站响应头Cache-Control缺失或no-cache响应头Cache-Control、ETag接口一直302未登录或被重定向到登录页请求是否携带Cookie/Authorization文件下载总触发CORS下载URL跨域且服务端未开放响应头Access-Control-Allow-Origin502 Bad Gateway上游服务崩溃、网关到上游不通上游进程、端口、日志、直连测试504 Gateway Timeout上游处理慢网关超时接口耗时、网关超时配置页面能开但接口502接口服务独立部署可能挂了接口服务健康检查、进程状态HTTPS安全警告证书过期、域名不匹配、证书链不全证书有效期、CN/SAN、中间证书6.2 一条可复用的排错路径拿到一个HTTP错误别急着改代码。我习惯按这个顺序查第一步看状态码确定是哪一类问题。4xx大概率是客户端请求写错了5xx大概率是服务端处理有问题。第二步看响应头。状态码只能定性响应头能定量。比如403时看WWW-Authenticate有没有提示认证方式429时看Retry-After重定向时看Location有没有给对跨域时看Access-Control-Allow-Origin。第三步看请求头。确认Host、User-Agent、Content-Type、Authorization、Cookie这些关键字段是否符合服务器预期。很多“神秘”的403其实只是缺了一个自定义头。第四步看请求body。确认格式是JSON还是表单字段名和接口文档完全一致。字段名多一个空格、少一个下划线都可能变成400。第五步看服务端日志。日志里会记录实际收到的请求路径、请求头、响应状态码。如果服务端日志显示没收到请求问题大概率在网络链路或网关层如果收到了但返回错误问题在应用层。6.3 我的几点实操心得最后说几个我自己踩过几次坑之后总结出来的点。一是手写HTTP报文时空行不能省Content-Length必须精确。这两个问题在自研客户端、嵌入式开发、socket编程里反复出现。建议无论如何都用抓包工具把实际发送的报文打出来看一眼很多诡异问题立刻就有答案。二是协议版本要一致。HTTP/1.0和HTTP/1.1在Connection默认值上不同1.0默认短连接1.1默认长连接。如果服务器和客户端对长连接的判断不一致会出现“响应收到但不结束”“连接一直挂着”的情况。三是HTTPS的证书问题要系统排查。证书过期、域名不匹配、证书链不完整这三类问题各有各的现象。检查证书最直接的方式是用openssl s_client命令能看到证书链、过期时间、SAN信息。四是不要盲目更换软件源或依赖源。遇到403、404这类状态码先确认源地址是否可信、是否被限制。不明渠道的镜像可能带来安全和供应链风险。五是请求头和响应头里的每一个字段都是有目的的。遇到问题多问一句“服务器为什么会这么回”多看一眼原始报文比在网上搜“xxx报错怎么解决”有用得多。HTTP协议并不复杂复杂的是它承载的各种业务逻辑。把基础打牢很多问题看一眼头字段心里就有数了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进