视频直链下载失败怎么办?MP4、WebM 排查

排查视频直链返回 403、404、CORS、空文件、格式不支持、无法断点续传等问题,附带 curl 诊断代码。

视频直链就是那种"一个 URL 一个文件"的下载:MP4、WebM、MOV、MKV,点开就能播放,拿到地址就能存。跟 M3U8、MPD 那种要拼分片再合并的流完全不是一回事。这篇文章把直链下载最常见的坑挨个过一遍,配 curl 命令帮你定位到底卡在哪。

先搞清楚:直链和流媒体不是一回事

直链下载失败的原因,一半以上是把流媒体的思维方式套到直链上。先分清这两类东西:

直链文件HLS / DASH 流
结构单个文件清单 + 成百上千分片
下载一个请求搞定逐片下载再合并
失败特征整包失败(403/404/空文件)部分分片失败、合并后花屏无声
排查方向请求头、地址有效性、格式清单、分片、密钥、合并

所以下面这些症状基本只属于直链。如果你的视频其实是 HLS 或 DASH 流,先去对应文章:M3U8(HLS)下载失败排查DASH 下载后无声排查。直链的检测与格式范围见 视频嗅探 — 支持的视频格式视频嗅探 — 直接视频文件

快速处理

先按这套流程走一遍,能解决八成问题:

  1. 打开视频实际播放的网页,播放几秒,确保视频真的加载了。
  2. 打开 FlowPick 扩展,从资源列表里挑视频文件,别选缩略图或封面。
  3. 确认右侧预览能正常播放,格式无误后点下载。

如果还是不行,按下面的症状对号入座。关于扩展里怎么选文件、怎么保存目录,见 使用方法 — 下载单个资源

症状一:403 Forbidden

现象:下载立刻失败,或者用浏览器直接打开这个地址也是 403。

直链视频很少真的"没权限",大多是请求头不对。源站常见的校验有:

  • Referer 校验:要求请求来自特定页面,空 Referer 或陌生来源直接拒绝。
  • Cookie / 登录态:没带登录 Cookie,或登录态已过期。
  • 临时令牌:URL 里带 ?token=xxx&expires=yyy,过期后返回 403。
  • 地区 / IP 限制:CDN 按出口 IP 决定给不给。

先抓出直链地址,用 curl 复现一下(把地址换成你自己的):

# 不带任何头的裸请求,看返回什么
curl -s -o /dev/null -w "裸请求: %{http_code}\n" "https://cdn.example.com/videos/lesson1.mp4"

# 带上页面 Referer 再试
curl -s -o /dev/null -w "带Referer: %{http_code}\n" \
  -H "Referer: https://www.example.com/course/123" \
  "https://cdn.example.com/videos/lesson1.mp4"

如果带 Referer 就好了,说明是防盗链校验。在浏览器扩展里解决:扩展运行在源页面上下文,Referer 和 Cookie 自动带上,v1.1.1 之后的版本还内置了防盗链代理,预览和下载都会自动补齐请求头并校验响应,不会把 HTML 错误页当视频存下来。在线工具没有这个能力——它运行在自己的域名下,带不了目标站点的 Cookie。升级方法见 安装指南 — 扩展更新,防盗链代理的细节见 FlowPick v1.1.1 更新

症状二:404 地址过期或文件已删除

现象:之前明明能下,今天 404;或者别人发的直链下不了。

常见三种情况:

  • 临时签名 URL 过期:很多云存储(阿里云 OSS、腾讯云 COS 等)的直链带有效期,过几分钟到几小时就失效。
  • 文件被清理:上传者删了文件,或 CDN 缓存被清掉。
  • 拿到了错误的地址:复制的是播放页地址,不是文件直链。

验证一下地址本身是不是活着:

curl -sI "https://cdn.example.com/videos/lesson1.mp4" | head -n 8

看返回的状态码和 Content-Type。如果 Content-Typetext/html,说明这个地址指向的是一个网页而不是视频。地址真的失效就没办法——回到原视频页面重新检测一次,拿新的直链再下。

症状三:CORS 跨域拦截

现象:在线工具报 CORS 错误,或者下载出来的文件是坏的。

这是在线工具特有的问题。在线工具跑在 flowpick.com 自己的域名下,浏览器同源策略会拦住跨域读取。扩展不一样,它拿的是扩展权限,不受同源策略限制,检测范围也更广。两者差异见 在线工具 — 与扩展的区别视频嗅探 — 扩展与在线工具的检测差异

解决办法就一句:别用在线工具下直链,改用扩展。扩展在视频原页面里工作,Referer、Cookie、跨域问题一次全解决。

症状四:下载到的是空文件或打不开

现象:下载"成功",但文件只有几 KB,或者播放器打不开。

十有八九是选错对象了:选中的不是视频文件,而是 HTML 页面、缩略图、封面图或预览接口的响应。这类响应的特征是体积很小,且 Content-Typetext/htmlimage/*

用 curl 看这个地址到底返回什么:

curl -sI "https://cdn.example.com/cover/lesson1.jpg"
# 看 Content-Type 和 Content-Length

如果指向的是 text/html,那它只是个网页。回到扩展,从资源列表里选 video/mp4video/webm 这类 video/* 类型的条目,再确认右侧预览能播放后再下载。如果文件名带乱码或者不带扩展名,下载后手动补上 .mp4 再试。

症状五:无法暂停、无法断点续传

现象:下载能开始,但点了暂停再继续,又从 0 开始;或者压根没有暂停按钮。

这跟服务器支不支持 HTTP Range 有关。Range 允许客户端只请求文件的一部分,暂停续传就靠它。服务器没开 Range,浏览器就只能整文件下载,自然没法断点继续。

测一下服务器支不支持:

curl -s -o /dev/null -w "Range请求: %{http_code}\n" \
  -H "Range: bytes=0-1023" \
  "https://cdn.example.com/videos/lesson1.mp4"
# 206 = 支持 Range,可以断点续传
# 200 = 返回了完整文件,说明不支持 Range

返回 206 说明支持;返回 200(完整文件)则不支持。不支持也照样能下载,只是不能断点继续,网络不好的时候建议一次下完别中断。这是服务器能力问题,不是工具问题。

症状六:格式或编码不支持

现象:文件下下来了,体积正常,但播放器报"格式不支持"或黑屏。

先分清容器编码两个概念:.mp4 是容器,里面装的可能是 H.264,也可能是 H.265/HEVC 或 AV1。容器支持不等于编码支持,播放器要能解码里面那层编码才能放出来。常见坑:

情况表现处理
MP4 内是 H.265/HEVC老播放器黑屏转成 H.264 或换播放器
WebM 内是 AV1硬件解码不支持转成 H.264/VP9
高清直链很大浏览器内存吃紧见下一节

检测和下载直链时 FlowPick 会读出编码信息。如果确认是编码不支持,用 格式转换 转成兼容性更好的 H.264 MP4 即可。你的播放器到底支持什么,可以参考 浏览器兼容性

症状七:大文件或浏览器卡住

现象:几百 MB 的直链下载到一半页面卡死,或下载完后浏览器明显变卡。

浏览器里存文件要过内存。FlowPick 优先走 File System Access API(选目录后流式写入,不占内存),不支持时退回 StreamSaver 或 Blob。其中 Blob 模式要把整个文件先装进内存,大文件就可能卡住。Blob 模式的具体硬限制见 已知限制 — Blob 模式硬限制,对应的已知问题见 已知限制 — 大文件 Blob 下载可能卡住

对策:

  • 优先选"选择保存目录",触发 File System Access API,大文件也能流式写。
  • 没这个按钮的浏览器(或移动端),把视频切到较低画质再下。
  • 实在要下大文件,一次只下这一个,别同时挂一堆下载。

诊断工具速查

F12 打开开发者工具,按这张表快速定位:

想确认什么面板做法
直链请求返回几Network筛选 mp4 / webm,看 Status 列
返回的是不是视频Network看响应头的 Content-Type 是否为 video/*
有没有带 Referer/CookieNetwork → 请求 → Headers看 Request Headers
是不是被 CDN 限速Network看单个请求的耗时和下载速度

如果你怀疑是浏览器环境问题,在 Console 里跑这段生成环境报告,反馈时贴出来:

const report = {
  ua: navigator.userAgent,
  fsa: 'showDirectoryPicker' in window,
  sab: typeof SharedArrayBuffer !== 'undefined',
  coi: self.crossOriginIsolated,
  storage: await navigator.storage?.estimate().catch(() => null),
  ts: new Date().toISOString(),
}
console.log(JSON.stringify(report, null, 2))

报告只含浏览器环境信息,不涉及任何浏览记录或个人数据。

什么时候真的下不了

  • DRM 保护:Widevine / PlayReady / FairPlay 加密的内容,FlowPick 明确不支持,也不做破解。
  • 登录或付费墙:不登录/不购买就拿不到直链地址的内容。
  • 接口私有化:视频数据走私有协议或需要应用内签名,不发普通直链。
  • 地址永久失效:源站已删除文件。

这些是设计上不支持,不是 bug。遇到就换个思路:录屏或联系内容方获取授权。更完整的边界清单见 已知限制

相关文档