Chain: client -> workerA -> workerB (RPC) -> workerC -> target URL (e.g., https://httpbin.org/get)
目标:观测 Cloudflare 在出站时会追加哪些请求头(如 CF-Connecting-IP、CF-Worker),以及在多级 Worker 链路中通过“请求头清洗”能够阻断多少敏感信息在下游继续传播。
- 客户端 →
worker-a(入口)→worker-b(通过 Service Binding 调用env.C)→worker-c(对外发起最终上游请求)→ 目标站点(默认https://httpbin.org/get)
worker-a/:绑定服务B,解析路径中的目标 URL 并向 B 转发(带x-target-url)worker-b/:绑定服务C,以 RPC 方式调用env.C.callUpstream(headersObj, targetUrl)worker-c/:实现 RPC 入口CService,对目标站点发起请求并回传上游回显scripts/:一键脚本(部署、测试、销毁)
- 已安装并登录 Wrangler(
wrangler login) - 使用相同 Cloudflare 账号/空间
- 赋予可执行权限:
chmod +x scripts/*.sh
- 一键部署→测试→销毁:
export SUBDOMAIN=<你的 workers.dev 子域名>
./scripts/run_once.sh https://httpbin.org/get
流程:部署 C→B→A,测试访问 A,然后自动销毁 A、B、C。
- 分步操作:
# 部署(C→B→A)
./scripts/deploy.sh
# 测试(脚本会构造路径 /<目标URL> 或 /upstream/<目标URL>)
./scripts/test.sh https://cfworkers-proxy-test-a.<subdomain>.workers.dev https://httpbin.org/get
./scripts/test.sh -u https://cfworkers-proxy-test-a.<subdomain>.workers.dev https://httpbin.org/get # 仅查看上游收到的头
# 清理
./scripts/destroy.sh
/<target-url>:返回分层调试信息(A/B/C 三层的receivedHeaders+upstream回显)/upstream/<target-url>:仅返回“上游服务实际收到的请求头”(例如 httpbin 的headers字段)/health:健康检查
- 默认访问
/<target-url>并打印响应头与 JSON(自动美化) - 请求时会附带
X-Debug: 1(浏览器直接访问时通常无该头)
为避免泄露原始客户端信息与链路信息,我们会在每一跳对出站请求头进行清洗,屏蔽:
cf-*、x-forwarded-*、x-real-ip、true-client-ip、forwarded、via、cookie、authorization、origin、referer、host、connection、proxy-*、sec-*。
注意:Cloudflare 在 Workers 对外(到公网)请求时,仍会注入部分 CF-* 头(如 Cf-Connecting-Ip 为 Cloudflare 出口 IP、Cf-Worker 等)。这些头无法完全去除,属于平台行为。
- 目标网站看不到你的原始客户端 IP/国家;它会看到 Cloudflare 的出口信息以及
Cf-Worker标识。 - 原始客户端的接入信息(如
cf-connecting-ip、cf-ipcountry)仅在 A(入口)处可见,并不会被继续传递给 B/C 或目标站点。
- 错误 “Unknown argument: yes”:已修复,
scripts/destroy.sh使用wrangler delete --name <worker> --force test.shPython 报错:已改为一行命令做 URL 编码- 如果
/upstream/...无内容,检查 A→B→C 的绑定是否部署成功,或目标 URL 是否可访问
worker-a/-> calls B via Service BindingBworker-b/-> calls C via Service BindingCworker-c/-> fetches upstreamUPSTREAM_URL(default httpbin)
Each hop sanitizes outgoing headers to avoid leaking client IP/geo via user-controlled headers. Blocklists include: cf-*, x-forwarded-*, x-real-ip, true-client-ip, forwarded, via, cookie, authorization, origin, referer, host, connection, proxy-*, sec-*. Note: Cloudflare may still inject CF-* headers on egress to the public Internet; this is expected and part of the test.
Service Bindings require the bound services to be reachable in Cloudflare. Recommended flow:
- Deploy worker C first:
wrangler deploy --config worker-c/wrangler.toml
- Deploy worker B (binds to C):
wrangler deploy --config worker-b/wrangler.toml
- For quick iteration on worker A, use remote dev (so the binding to B works):
wrangler dev --remote --config worker-a/wrangler.toml --port 8781
Then call worker A, specifying the final upstream in the path:
# Example: target https://httpbin.org/get
curl -i 'http://127.0.0.1:8781/https://httpbin.org/get' -H 'X-Debug: 1'
You should get a JSON response containing:
- headers seen by workers A and B
- upstream JSON (what it saw from worker C)
Production deployment order should be C -> B -> A. The [[services]] bindings in:
worker-a/wrangler.tomlbindBto servicecfworkers-proxy-test-bworker-b/wrangler.tomlbindCto servicecfworkers-proxy-test-c
- You cannot fully prevent Cloudflare from adding certain
CF-*headers on egress to the public Internet from Workers today. This test helps you see exactly what shows up at the destination. - We aggressively sanitize outgoing headers (
cf-*,x-forwarded-*,x-real-ip, etc.) to ensure only Cloudflare’s platform additions remain when talking to the public Internet.