7.0 KiB
7.0 KiB
XHR/fetch Live Session Bridge
本文件用于约束 Node.js 补环境中的 XMLHttpRequest、fetch、Request、Response、Headers 与 navigator.sendBeacon。当最终项目会发送真实请求,或这些 API 影响动态资源、Cookie、challenge、telemetry、resource timing、writer 分支时,JS 侧网络 API 必须复用最终确认的 TLS 指纹兼容 Session。
硬性规则
offline-fixture只能用于离线诊断:可以返回 fixture / 默认响应,但必须明确标注“不发送真实网络请求”,不得宣称 TLS 指纹问题已解决。live-session-bridge用于真实验证:JSXMLHttpRequest/fetch/sendBeacon必须把请求交给同一个 CycleTLS / impers / curl-cffi-node / curl_cffi / cffi_curl / cyCronet Session 发送。- 不得在补环境网络对象内部直接调用 Node 宿主
fetch、http、https、axios、undici或 Python 普通requests绕过已确认 TLS 客户端。 - 如果最终用户选择 Python
curl_cffi,final.py必须持有唯一curl_cffi.requests.Session();Node JS runtime 通过 stdio / IPC / 嵌入式 bridge 请求 Python 发送,Node 侧只实现浏览器 API 语义与桥接协议。 - Bridge 只能作为唯一
final.js/final.py入口内部的受控模块存在,不得交付另一个手动启动入口、临时 HTTP server、调试 bridge 或常驻本地服务。 - XHR/fetch 对象本身不得通过
_/__自有属性保存状态;状态用 addon / xbs private API 或模块级WeakMap。 - Session Bridge 只证明“由哪个客户端发送”,不能证明请求语义正确。真实请求前必须继续按
xhr-fetch-semantics-audit.md比较浏览器与 Node 的 no-send network transcript。 - 代码里出现
curl_cffi、IPC、sessionBridge等关键词不算验收证据;必须有运行时xhr-fetch-bridge-audit.json和机器生成的xhr-fetch-semantics-audit.json。
推荐架构
目标 JS XMLHttpRequest/fetch
-> src/env/network/xhr.js / fetch.js 浏览器语义层
-> session bridge adapter
-> final.js/final.py 持有的同一 TLS Session
-> 目标网络请求
-> response envelope
-> JS XHR readyState / fetch Response / resource timing / Cookie 同步
Python curl_cffi 场景:
final.py
create curl_cffi.requests.Session()
spawn Node runtime child process
read NDJSON bridge request from child stdout / pipe
session.request(...)
write NDJSON bridge response back to child stdin / pipe
finally session.close()
Node 侧不得自行发目标 URL 请求;只发 bridge envelope。Python 侧不得创建第二个 Session 给 XHR/fetch,必须复用最终请求同一个 session。
Bridge 请求 envelope
至少记录:
{
"id": "bridge-req-1",
"api": "XMLHttpRequest.send",
"method": "POST",
"url": "https://example.com/api",
"headers": {},
"bodyEncoding": "utf8/base64/bytes/none",
"body": "",
"credentials": "include/same-origin/omit",
"referrer": "",
"mode": "cors/same-origin/no-cors",
"timeoutMs": 30000,
"baselineId": "fp-001"
}
Bridge response 至少记录:
{
"id": "bridge-req-1",
"ok": true,
"status": 200,
"statusText": "OK",
"headers": {},
"bodyEncoding": "utf8/base64/bytes",
"body": "",
"timing": {},
"setCookieApplied": true
}
浏览器语义同步
XMLHttpRequest.open()、setRequestHeader()、send()、abort()、timeout、responseType、readyState、status、responseText、responseURL、getResponseHeader()、getAllResponseHeaders()按目标浏览器采样实现。fetch()返回Promise<Response>,Headers、Request、Response.clone()、text()、json()、arrayBuffer()、body used 状态应可审计。Set-Cookie由 session client 写回 Cookie jar,并同步到 JS cookie store;xhr.getResponseHeader("set-cookie")和fetch Response.headers.get("set-cookie")默认应为null,除非目标浏览器 baseline 证明可见。document.cookie写入必须进入同一 Cookie jar 或在 bridge 请求前合并;服务端Set-Cookie必须更新同一 jar 和 JS cookie store。- resource timing 如果被目标检测,必须在
PerformanceResourceTiming中记录与真实浏览器 baseline 一致的最小字段和可见时机。 - CORS、redirect、referrer、credentials、cache、keepalive、sendBeacon 是否完整实现取决于目标路径;未覆盖时在矩阵中标
needs-browser-baseline或native-capability-gap,不得静默 mock。
必须产物
真实请求场景至少生成:
case/notes/xhr-fetch-session-bridge.md
case/tmp/xhr-fetch-bridge-audit.json
case/fixtures/browser-network-transcript.ndjson
case/tmp/node-network-transcript.ndjson
case/tmp/xhr-fetch-semantics-audit.json
xhr-fetch-session-bridge.md 记录:
- 网络模式:
offline-fixture/live-session-bridge/ 不涉及。 - 最终 TLS Session 客户端:CycleTLS / impers / curl-cffi-node / curl_cffi / cffi_curl / cyCronet。
- Session 持有者:
final.js/final.py。 - JS bridge 文件:例如
result/src/env/network/xhr.js、result/src/env/network/fetch.js。 - 请求层文件:例如
result/src/request/client.js或result/src/request/session_client.py。 - Cookie / Set-Cookie 同步策略。
- readyState / Promise / event 顺序验证。
- resource timing 是否涉及。
- 离线 fixture 是否仅用于诊断。
- Session id、运行时 bridge round trip 数、
sameSessionVerified、runtimeSourceHash。 - no-send 请求语义审计结果:请求来源、Header 顺序、body SHA256、status/responseURL、事件顺序、reload realm 清理。
xhr-fetch-bridge-audit.json 必须由运行时 bridge 在至少一次受控 round trip 后写出:
{
"schemaVersion": "xhr-fetch-session-bridge-audit/v2",
"generatedBy": "runtime-session-bridge/v2",
"mode": "live-session-bridge",
"tlsClient": "curl_cffi",
"sessionOwner": "final.py",
"sessionId": "session-1",
"transportRoundTrips": 1,
"sameSessionVerified": true,
"runtimeSourceHash": "...",
"cookieSyncVerified": true
}
不得在没有实际 bridge round trip 时生成该文件。Node no-send transcript 和最终请求 session 必须记录同一 session identity 或可验证的 session lineage。
检查命令
node scripts/check_xhr_fetch_session_bridge.js --case-dir case --markdown
node scripts/check_xhr_fetch_session_bridge.js --case-dir case --require-live --json
node scripts/check_xhr_fetch_session_bridge.js --case-dir case --tls-client curl_cffi --require-live --markdown
node scripts/check_xhr_fetch_semantics.js --case-dir case --require --require-no-send --out case/tmp/xhr-fetch-semantics-audit.json --markdown
检查失败时,下一步只能补 live session bridge、补 Cookie 同步、修正 XHR/fetch 浏览器语义、改为明确不发真实请求,或记录用户豁免。不得继续真实请求验证或写“TLS 指纹已解决”。