///
CapMonster Cloud 的 Header 顺序:如何复现浏览器请求头并绕过反机器人保护
Vladlen Vlasov
Vladlen Vlasov
技术撰稿人
April 20, 2026
5 分钟
请查看本网站所提供内容的使用条款。

CapMonster Cloud 的 Header 顺序:如何复现浏览器请求头并绕过反机器人保护

generated-image.png

在自己的网站上测试保护系统并使用 CapMonster Cloud 服务时,许多开发者都会遇到这样一种情况:CAPTCHA 已成功求解,令牌也已获取——但服务器仍然拒绝该请求。

当你实现 CAPTCHA 或反机器人机制时,你需要准确理解服务器是如何作出判断的——以及它使用哪些信号来识别自动化行为。问题通常不在于 CAPTCHA 本身,而在于 HTTP 请求是如何发送的。

其中一个关键因素是请求头顺序。在本文中,你将了解为什么顺序很重要、如何正确复现它,以及如何将其与 CapMonster Cloud 集成。

robots
立即开始自动化您的工作流 reCAPTCHA v2

什么是请求头顺序

一个 HTTP 请求不仅由 URL 和请求体组成,还包含一组请求头:

User-Agent
Accept
Accept-Language
Cookie
...

服务器不仅会读取请求头的内容——它还会看到它们的顺序。

为什么这对反机器人保护很重要

现代保护系统(Cloudflare、DataDome、Imperva 等)会分析:

  • TLS 指纹(JA3/JA3S)
  • HTTP/2 SETTINGS 指纹(Akamai H2 fingerprint)
  • User-Agent
  • IP 声誉(ASN、数据中心 IP 或住宅 IP)
  • JavaScript 指纹
  • 请求头顺序
  • 客户端行为

真实浏览器(Chrome、Firefox 等)发送请求头时会:

  • 按照严格定义的顺序发送
  • 在每次请求中都保持一致

但常见的 HTTP 库——requests(Python)和 axios(Node.js)——可能会在用户定义的请求头之外添加默认请求头(User-Agent, Accept-Encoding, Connection),对请求头进行排序,或以随机顺序发送它们,这会破坏预期的顺序并暴露自动化特征。

这与 CapMonster Cloud 有什么关系

CapMonster Cloud 只负责求解 CAPTCHA,并不会让你的请求“看起来像浏览器发出的”。

也就是说:

  1. 你收到了一个有效的 token
  2. 把它添加到了请求中
  3. 但服务器仍然返回错误

为什么?因为你的请求看起来像一个机器人。

浏览器如何发送请求头(Chrome 146*)

在真实浏览器中,这种顺序几乎每次都会重复出现:

* 在撰写本文时,Chrome 146 是当前版本。

HTTP/2 伪请求头

:method
:authority
:scheme
:path

常规请求头(Chrome 示例)

sec-ch-ua
sec-ch-ua-mobile
sec-ch-ua-platform
upgrade-insecure-requests
user-agent
accept
sec-fetch-site
sec-fetch-mode
sec-fetch-user
sec-fetch-dest
accept-encoding
accept-language
priority

一个常见错误——从 DevTools 复制

很多开发者会这样做:

  1. 打开 Chrome DevTools
  2. 复制请求头
  3. 将它们粘贴到代码中

问题在于:

  • DevTools 并不总是显示真实顺序,而且可能会对请求头进行排序
  • 因此,代码中的顺序会与浏览器中的顺序不同

如何获取正确的顺序

使用能够显示真实请求的工具:

  • Charles Proxy
  • mitmproxy
  • powhttp

它们显示的请求头顺序与服务器看到的完全一致。

例如(使用 Charles Proxy 抓取):

:method: GET
:authority: example
:scheme: https
:path: /assets/js/example.js
sec-ch-ua-full-version-list: "Chromium";v="146.0.7680.178", "Not-A.Brand";v="24.0.0.0", "Google Chrome";v="146.0.7680.178"
sec-ch-ua-platform: "Windows"
sec-ch-ua: "Chromium";v="146", "Not-A.Brand";v="24", "Google Chrome";v="146"
sec-ch-ua-bitness: "64"
sec-ch-ua-model: ""
sec-ch-ua-mobile: ?0
sec-ch-ua-arch: "x86"
sec-ch-ua-full-version: "146.0.7680.178"
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36
sec-ch-ua-platform-version: "19.0.0"
accept: */*
sec-fetch-site: same-origin
sec-fetch-mode: no-cors
sec-fetch-dest: script
referer: https://example.com/
accept-encoding: gzip, deflate, br, zstd
accept-language: en-US,en;q=0.9,ru;q=0.8
priority u=0, i

如何在代码中复现请求头顺序

一旦你拿到了真实的请求头顺序,下一步任务就是在 HTTP 客户端中正确复现它。

关键问题在于,大多数标准库都不保证请求头顺序。

工具

顺序控制

HTTP/2

TLS 指纹

requests

axios

部分支持

tls-client

Playwright

✅(浏览器)

为了准确复现浏览器行为,建议使用专门的解决方案:

  • tls-client(Go / Python)——通过 Go 绑定层的 header_order + pseudo_header_order 实现请求头顺序控制 bogdanfinn/tls-client,并将这些参数直接传递给原生库
  • 自定义 HTTP/2 客户端
  • 浏览器自动化(例如 Playwright)——如果可以接受其额外开销

配置示例(Python + tls-client)

下面的示例演示了复现类似 Chrome 的请求头顺序的一种基础方法。

重要提示:chrome_146 是 Go 库 bogdanfinn/tls-client 中的有效 profile,文档中标注为 “Latest”。不过,标准 Python 包 FlorianREGAZ/Python-Tls-Clientpip install tls-client)已经停止维护,且只包含到 chrome_120 为止的 profile。读者如果安装标准包,将会收到错误。请使用当前的 bogdanfinn/tls-client 分支,或使用支持 chrome_146 的兼容 Python 绑定。

import tls_client

session = tls_client.Session(
    client_identifier="chrome_146",
    random_tls_extension_order=True
)

session.pseudo_header_order = [
    ":method",
    ":authority",
    ":scheme",
    ":path",
]

session.header_order = [
    "sec-ch-ua",
    "sec-ch-ua-mobile",
    "sec-ch-ua-platform",
    "upgrade-insecure-requests",
    "user-agent",
    "accept",
    "sec-fetch-site",
    "sec-fetch-mode",
    "sec-fetch-user",
    "sec-fetch-dest",
    "accept-encoding",
    "accept-language",
    "cookie",
    "priority",
]

headers = {
    "sec-ch-ua": '"Chromium";v="146", "Not-A.Brand";v="24", "Google Chrome";v="146"',
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": '"Windows"',
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/146.0.0.0 Safari/537.36",
    "accept": "*/*",
    "sec-fetch-site": "same-origin",
    "sec-fetch-mode": "no-cors",
    "sec-fetch-dest": "script",
    "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "en-US,en;q=0.9",
    "priority": "u=0, i",
}

response = session.get("https://example.com", headers=headers)
print(response.status_code)

session.header_order 中的顺序必须与您从真实浏览器中获取到的顺序一致。任何偏差都可能影响结果。


HTTP/2 SETTINGS 指纹

反机器人系统分析的不仅仅是请求头——它们甚至会在解析请求头之前检查 HTTP/2 SETTINGS 指纹。Cloudflare 和 DataDome 使用所谓的 Akamai H2 fingerprint,它会将各项参数编码为如下格式的字符串:

SETTINGS|WINDOW_UPDATE|PRIORITY|PSEUDO_HEADER_ORDER

这种信号可以在不分析请求内容的情况下,立即识别出 curlrequestsaxiostls-client 通过 client_identifier 自动解决了这个问题:它会为所选浏览器应用正确的 H2 SETTINGS profile。这就是为什么参数 client_identifier="chrome_146" 不只是一个“Chrome 版本”,而是整个网络栈的完整 profile。


robots
立即开始自动化您的工作流 reCAPTCHA v2

CAPTCHA 求解后 Cookie 的作用

在成功通过 CAPTCHA 后,服务器通常还会设置额外的 Cookie。根据所使用的保护系统不同,这些 Cookie 可能包括:

  • cf_clearance(Cloudflare)
  • datadome(DataDome)
  • visid_incap(Imperva)

这些 Cookie 会成为后续会话的一部分,并且必须在之后的请求中一并发送。

cookie 请求头必须出现在 Header Order 中的正确位置。如果它:

  • 没有包含在请求头顺序列表中
  • 或被自动追加到末尾

这都可能破坏预期的请求结构,并导致请求被拒绝。

在 tls-client 中通过 session 传递 Cookie 的示例:

import tls_client

session = tls_client.Session(
    client_identifier="chrome_146",
    random_tls_extension_order=True,
)

# 在从 CapMonster Cloud / 手动获取 cf_clearance 后 —— 将其传入 session
session.cookies.set(
    "cf_clearance",
    "received_value",
    domain=".example.com",
)

# 后续所有请求都会自动在正确位置包含该 cookie
response = session.get(
    "https://example.com/protected-page",
    headers=headers,
)

print(response.status_code)

影响结果的其他错误

请求之间的请求头不一致

真实浏览器会使用稳定的一组请求头。如果你的脚本:

  • 在不同阶段发送不同的请求头
  • 改变它们的顺序
  • 无规律地添加或删除请求头

这会被视为异常。


Referer 不正确

referer 请求头在导航上下文中起着重要作用。它缺失或不匹配都可能显得可疑。

例如,如果你请求的是某个通常从页面中加载的资源,却没有指定 referer,这可能会触发额外检查。


sec-fetch 请求头不匹配

Sec-Fetch-SiteSec-Fetch-ModeSec-Fetch-Dest 请求头必须与真实的请求上下文一致。Sec-Fetch-Site 表示发起方与目标资源之间的关系,Sec-Fetch-Mode 表示请求模式,而 Sec-Fetch-Dest 表示所加载资源的目标类型。

错误或不一致的取值可能会与 HTTP 请求中的其他数据相矛盾,并被服务器用作拒绝请求的信号。错误在以下情况下尤其常见:对正常链接点击使用 none,或者将 cross-origincross-site 混淆。

根据请求类型对应的正确取值表:

场景

sec-fetch-site

sec-fetch-mode

sec-fetch-dest

在地址栏中直接输入 URL / 打开书签

none

navigate

document

点击链接进入同一 origin 的页面

same-origin

navigate

document

点击链接进入同一站点但不同 origin 的页面

same-site

navigate

document

点击链接进入另一个站点

cross-site

navigate

document

向同一 origin 发起 fetch() / XHR

same-origin

cors

empty

向同一站点但不同 origin 发起 fetch() / XHR

same-site

cors

empty

向另一个站点发起 fetch() / XHR

cross-site

cors

empty

从同一 origin 加载图像

same-origin

no-cors

image

从另一个站点加载图像

cross-site

no-cors

image


使用 HTTP/1.1 而不是 HTTP/2

包括 Chrome 在内的现代浏览器默认使用 HTTP/2。

如果你的客户端通过 HTTP/1.1 工作,这本身就会造成明显差异。再结合其他因素,这可能会影响反机器人系统的判断。


硬编码 sec-ch-ua-full-version-list

sec-ch-ua-full-version-list 请求头只会在响应服务器返回的 Accept-CH 时出现(Client Hints API)——它不会自动出现在每个请求中。在“冷启动”请求中,它根本不应出现。

在代码中硬编码这个请求头,可能会导致 User-Agentsec-ch-ua 与真实 TLS profile 之间不匹配。结果就是,请求看起来前后不一致,并可能被反机器人系统拒绝。

在某些情况下(例如处理 DataDome 时),更安全的做法是,要么从真实流量中获取它,要么在没有必要时不要手动设置它。


重复的 Cookie

另一个常见错误是发送多个同名但值不同的 Cookie。例如:

image.png

这种情况可能发生于:

  • 在不使用 cookie jar 的情况下手动管理 Cookie
  • 库错误地合并了 Cookie
  • 值被重复设置

正确的做法是:

  • 使用内置的 Cookie 管理机制(cookie jar)
  • 在发送前检查最终的 cookie 请求头
  • 避免重复的名称

实用的调试方法

诊断问题最可靠的方法,是将真实浏览器请求与你自己的请求进行对比。

推荐流程:

  1. 使用 Charles Proxy 或 mitmproxy 等工具从浏览器中抓取请求
  2. 从你的代码中执行相同的请求
  3. 逐行比较两者

需要特别关注:

  • 请求头顺序
  • 特定请求头是否存在
  • 请求头取值
  • Cookie

即使是很小的差异也可能很重要。


结论

CapMonster Cloud 服务可以帮助获取正确的 CAPTCHA 解答,但之后在你的应用中如何处理和使用该解答,仍然由你自己负责。

例如,Cloudflare Bot Management 会同时检查 TLS、H2 SETTINGS 和请求头——只要某一层失败,就足以触发拦截。要想成功与受保护系统交互,你需要:

  • 在 HTTP 层面复现浏览器行为
  • 保持精确的请求头顺序
  • 通过 client_identifier 使用正确的 TLS profile 和 H2 SETTINGS
  • 保持请求一致性
  • 通过 cookie jar 正确处理 Cookie

只有将这些因素结合起来,才能在测试和处理反机器人保护时获得稳定结果。


NB: 请注意,本产品仅用于对您自身的网站以及您依法拥有访问权限的资源进行自动化测试
ItGuy
geear
面向软件开发者的联盟计划
通过用户识别验证码的消费获取高达 30% 的返佣。
✅ 请求已发送
感谢您对我们的合作伙伴计划感兴趣!我们将在 7 个工作日内与您联系。
请求加入
填写表格以提交申请加入合作伙伴计划。
更多文章