
前言做接口调试、爬虫开发时大家都有一套标准操作流程浏览器F12 Network面板右键请求复制 cURL(bash)再转换成 Python requests 代码直接运行。但经常遇到一种非常迷惑的现象完整携带浏览器复制出来的所有请求头接口返回 403、405、鉴权失败、校验不通过手动删除其中几个请求头之后请求立刻恢复正常。很多人只能靠“试错删Header”盲调知其然不知其所以然。本文系统性梳理造成该现象的全部原因、高危请求头清单、排查思路与最佳实践。前置说明本文讨论范围requests/aiohttp等Python HTTP客户端和原生Chrome浏览器行为差异。一、核心本质浏览器Header≠通用合法Header浏览器自动携带大量浏览器专属安全请求头。这些头部是 Chrome、Edge 内部用于浏览器安全策略、同源校验、环境标识。服务端、WAF、风控系统会根据这些头部结合客户端特征做校验当Python客户端携带浏览器专属头却没有浏览器底层行为匹配时风控校验直接判定异常请求。简单一句话头部本身没有对错但是请求头和客户端行为不匹配触发服务端防护策略。二、造成请求失败高频高危请求头分类1. Sec-* 系列安全头最高发元凶典型列表Sec-Fetch-Dest Sec-Fetch-Mode Sec-Fetch-Site Sec-Fetch-User Sec-CH-UA Sec-CH-UA-Mobile Sec-CH-UA-Platform这一类是现代浏览器新增的Fetch Metadata 请求头。作用告诉服务端当前请求来源、页面上下文、跨域类型。关键原理只有 Chromium 内核浏览器才会自动生成、携带这套 Sec-* 头部requests、aiohttp 原生不支持浏览器底层安全上下文机制大量网站、WAF、后端风控逻辑如果请求带有 Sec-Fetch-* 系列头部则默认请求来自浏览器页面同时校验 Origin、Referer、Cookie上下文、跨域逻辑。当你在Python中强行带上Sec-Fetch-*但不存在真实浏览器页面环境风控判定请求头伪造属于异常爬虫直接返回403、拦截请求。✅ 解决方案绝大多数场景下可以直接删除全部 Sec-开头请求头*。2. Origin / Referer 校验陷阱很多人以为带上 Origin、Referer 就一定没问题这里存在两种坑Referer 地址与当前请求逻辑不匹配例如接口要求跳转来源是A页面但是复制的Referer固定会话上下文对不上部分服务端逻辑如果存在 Sec-Fetch-Site: same-origin会强制校验 Origin 是否和域名一致只保留 Sec-* 却不维护Origin会话校验直接失败。补充不要盲目删除建议策略没有出现拦截问题就保留出现403时可以尝试移除或者修正。3.Accept-Encoding编码陷阱浏览器默认Accept-Encoding: gzip, deflate, br问题Chrome 原生完整支持 brBrotli压缩默认 requests 库不自带 br 解码支持场景复现带上完整Accept-Encoding: gzip, deflate, br服务端返回 Brotli 压缩报文 → requests 无法自动解压 → 得到乱码响应程序解析失败。两种解决方式移除 br改为Accept-Encoding: gzip, deflate安装brotli库支持自动解压4.Connection: keep-alive极少翻车但容易混淆浏览器携带Connection: keep-aliverequests 默认也是长连接一般不会出错。极少数老旧网关、防火墙会基于该头部做连接特征识别一般不作为首要排查对象。5.TE,Sec-CH-UA用户代理客户端提示头Sec-CH-UA系列属于User-Agent Client Hints浏览器用来下发浏览器版本信息。风控系统会组合判断User-Agent和Sec-CH-UA内容是否一致。如果复制时两者配套携带一旦其中一处被修改特征不一致直接拦截。三、第二种重要原因cURL 复制附带--compressed容易被忽略从浏览器复制的 curl 命令默认带有--compressed转换成 requests 代码时很多工具不会处理这个参数。curl--compressed自动解压 gzip/brrequests依靠头部内置解压逻辑。出现现象头部完整照搬但是编码处理不一致响应异常、接口逻辑报错。四、第三种原因请求头大小写、多余空格、非法换行浏览器展示的头部看起来正常但复制过程存在隐藏字符部分后端服务、Nginx 对请求头格式严格校验多余空格直接触发校验失败。补充HTTP标准头部名称大小写不敏感但部分自研网关、WAF实现不规范存在严格匹配。五、第四种容易忽略Cookie上下文不匹配浏览器复制出来的 Cookie 是短期有效会话。即便你带上所有HeaderCookie 过期Cookie 绑定浏览器指纹、会话、IP此时单纯删Header不一定生效需要刷新浏览器重新复制。六、标准化排查步骤遇到此类问题直接套用先批量删除所有Sec-开头请求头重新测试80% 的 403 拦截问题都能解决检查Accept-Encoding确认是否包含 br 且环境不支持解压观察是否保留大量Sec-CH-UA客户端提示头按需删除区分报错类型403 Forbidden大概率风控、WAF识别特征异常优先处理Sec系列头返回乱码编码 Accept-Encoding 问题401/鉴权失败优先核对token、cookie时效性不要一次性全部删除建议二分法逐步移除头部定位到底是哪一个Header导致拦截。七、最佳实践Python爬虫通用Header模板不要无脑全量复制浏览器Header推荐精简模板importrequests headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...,Accept:text/html,application/xhtmlxml,application/xml;q0.9,*/*;q0.8,Accept-Language:zh-CN,zh;q0.9,Referer:https://xxx.com/}原则保留通用基础头部默认不携带 Sec-系列浏览器私有头部*。如果你需要模拟真实浏览器访问追求更高相似度可以保留少量头部但不要全套Sec-*一并带上。八、常见误区澄清❌ 误区这些请求头是非法的服务端不识别✅ 正解头部本身合法问题在于「头部声明的客户端环境」和Python程序真实环境不匹配触发风控校验。❌ 误区所有网站都要删除Sec-*头部✅ 正解大部分普通网站无校验可以完整携带只有开启WAF、具备反爬策略的站点才会拦截。❌ 误区浏览器能带上Python客户端就一定能带上正常访问✅ 正解HTTP头部只是一部分浏览器还有JS环境、指纹、TLS指纹、Cookie持久化、WebGL指纹等大量特征无法单纯依靠Header模拟。九、总结浏览器复制出来的全套请求头并不设计给非浏览器客户端直接使用。Sec-Fetch-*、Sec-CH-UA这类浏览器专属安全请求头是造成「全量复制请求失败、删除Header即可成功」的头号元凶。开发爬虫、调试接口记住一条准则*不要无脑复制浏览器全部请求头优先精简浏览器私有Sec系列头部遇到403拦截时优先清理Sec-开头请求头进行验证。单纯依靠请求头模拟浏览器早已不够高级反爬场景还需要考虑TLS指纹、JA3指纹、JS环境模拟等更多维度但Header优化是成本最低、最先排查的一环。