花拾录
← 返回知识库

命令行下载被 CDN 返回 403:403 不一定是你没权限

编程语言导入2026/09/220 阅读0 评论

一个下载任务全线失败,HTTP 状态码清一色是 403 Forbidden。你的第一反应可能是"地址错了"或者"没有权限"。但这次,问题其实出在一个更朴素的地方:对方觉得你不像浏览器。

现象

下载某类流媒体分片时,CDN 持续返回 403,全部失败,一个都没成功:

$ downloader --url "https://<cdn-host>/segment/0001.ts"
HTTP error 403: Forbidden
HTTP error 403: Forbidden
HTTP error 403: Forbidden
...

地址本身是对的(浏览器里能播),网络也是通的,可命令行工具就是拿不到数据。

根因

CDN 会拦截命令行工具的默认 UA(User-Agent)。当你用 curl、wget 或某个下载器发请求时,它们默认会带上类似 curl/7.88.1 这样的 UA 字符串。CDN 的风控规则看到这种"明显不是浏览器"的 UA,就直接返回 403。

这就是为什么这个现象特别有迷惑性:403 通常让人联想到权限,可这里压根不是权限问题——它是一个反爬/反脚本的拦截动作,只是恰好用了 403 这个状态码。

排查的关键在于:如果你在浏览器里能正常访问同一个 URL,但命令行工具不行,那基本可以断定是 UA(或者其它请求头)的差异导致的。

解决

把请求 UA 换成常见的浏览器 UA。具体看工具支持哪种方式:

# 下载器支持 -user_agent 参数时
downloader --url "https://<cdn-host>/segment/0001.ts" \
  -user_agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36"

如果是自己用 Python 发请求,就手动设置请求头:

import requests

HEADERS = {
    "User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                   "AppleWebKit/537.36 (KHTML, like Gecko) "
                   "Chrome/120.0 Safari/537.36"),
    "Referer": "https://<cdn-host>/",   # 有些 CDN 还会校验 Referer
}

resp = requests.get(segment_url, headers=HEADERS, timeout=15)
resp.raise_for_status()

如果只改 UA 还不够,可以继续对照浏览器实际发出的请求头(按 F12 打开开发者工具,看 Network 面板),把 Referer、Accept、Accept-Language 等关键头补齐。这是整件事里唯一卡住过的点——UA 一换,下载就通了。

延伸与预防

这个案例的通用教训是:403 不一定是权限问题,可能只是"你不像浏览器"。

以后再遇到 403,建议按这个顺序排查:

  1. 先确认地址和网络——浏览器能不能打开?能,就排除"地址错"和"被墙";
  2. 对比请求头——把你的请求和浏览器的请求头逐项对照,重点看 UA、Referer、Cookie;
  3. 再考虑权限——如果是需要登录的资源,才轮到 token/Cookie 的问题。

预防上,可以给采集脚本准备一套"浏览器化"的默认请求头,作为所有请求的基线;同时把 403 当成"信号"而不是"结论"——它提示你请求被识别为非浏览器流量,解决方向是"伪装成正常流量",而不是去查权限配置。

还有一个值得记住的区分:UA 引起的 403 往往是"稳定复现"的——同一个 URL,用命令行永远 403,用浏览器永远成功,不随时间变化。而如果是频率风控引起的,表现通常是"跑一阵子才开始 403"。两种症状指向不同的原因,排查时先看"是不是每次都失败",能帮你快速分流。

顺带一提,UA 只是众多反爬维度之一。做得更严的站点还会看 TLS 指纹、请求频率、行为模式。但对大多数"403 挡命令行工具"的场景来说,换个 UA 就已经够了。真遇到更严的,再考虑上更完整的浏览器指纹方案,不必一上来就把工具链搞得那么重。

评论(0)

  • 还没有评论,来抢沙发~

相关文章