ZWCorsProxy:在浏览器播放任意跨域视频的本地 CORS 反向代理(mp4 + m3u8)

跨域视频在 <video> 标签或 hls.js 里放不出来,因为源服务器不发送 CORS 头。ZWCorsProxy 用一招解决:在 URL 前加上本地前缀。代理在服务端取回内容、注入宽松 CORS 头再返回——mp4 透明转发(Range/206 完整保留),m3u8 播放列表自动重写分片 URL 让整条流都经代理。单文件二进制、零依赖、强制绑 127.0.0.1 永远不会变成开放代理。

下载(预编译,免安装):

免费 · 单文件自包含二进制 · 无需运行时 · 无需注册


为什么浏览器放不了跨域视频

你把一个视频嵌入网页——比如产品演示或托管在 CDN 上的 HLS 流——播放器就是加载不出来。控制台报一个红色的 CORS 错误“已拦截跨源请求:请求的资源上不存在 ‘Access-Control-Allow-Origin’ 头。”

这是因为浏览器执行同源策略yoursite.com 上的脚本不允许读取 cdn.example.com 的响应,除非该 CDN 通过 Access-Control-Allow-Origin 头明确允许。而大多数视频 CDN、防盗链源、媒体服务器根本不发这个头。

你改不了远端服务器的响应头。所以让视频能播放的唯一办法,是从一个不受 CORS 约束的地方去取——这正是服务端进程能做的事。ZWCorsProxy 就是这个进程,跑在你本机上。

ZWCorsProxy 做了什么

启动一次。然后对任意跨域视频,在 URL 前加上本地代理前缀:

http://127.0.0.1:8000/?url=https://cdn.example.com/video.mp4

代理做三件事:

  1. 在服务端取回该 URL(Go 的 HTTP 客户端不受浏览器 CORS 约束)。
  2. 注入宽松 CORS 头(Access-Control-Allow-Origin: * 等)后再返回。
  3. 对 m3u8/HLS,把播放列表里的每一个内部 URL(分片、密钥、变体)都重写成指向本代理,让整条流都经代理。

因为它跑在回环接口(127.0.0.1)上,没有额外的网络往返开销——速度只受上游连接带宽限制。

核心特性

特性 说明
mp4 透明转发 二进制流原样透传,Range / 206 / Content-Range 完整保留——拖动进度条零延迟。
m3u8 自动重写 播放列表的分片 URL、#EXT-X-KEY 的 URI、master 变体都重写成指向代理的 base64 路径,HLS 每一级请求都 CORS 干净。
宽松 CORS 每个响应都带 Access-Control-Allow-Origin: *,且 Expose-HeadersContent-Range, Accept-Ranges, Content-Length——hls.js 需要的头都有。
Range / 拖动支持 正确处理 Range 请求并返回 206 Partial Content(视频代理最常见的坑——返回 200 弄坏进度条——已避免)。
安全绑定 默认绑 127.0.0.1(回环)。可用 -host 绑定本机其它网卡 IP(如局域网 IP,供其它设备访问);0.0.0.0 被拒绝,防止变成开放代理。
SSRF 防护 拒绝代理到私网段(10.x172.16-31.x192.168.x)、回环、链路本地、云元数据(169.254.169.254)、IPv6 ULA(fc00::/7)以及非 HTTP 协议。
可选 HTTPS -https 用内嵌的 30 年自签证书跑 TLS(与 ZWServe 共用同一张证书,信任一次两个工具都能用)。
防盗链支持 -referer 可伪造 Referer 头,对付校验来源的防盗链站。
零依赖 每个平台一个自包含 Go 二进制。无需运行时、无需 node_modules、免安装。

三端快速上手

Windows

双击 zwcorsproxy-win.exe,或在 PowerShell / cmd 里:

.\zwcorsproxy-win.exe
.\zwcorsproxy-win.exe -port 9000

macOS(Apple Silicon)

chmod +x zwcorsproxy-macos
./zwcorsproxy-macos
./zwcorsproxy-macos -port 9000

macOS 版针对 Apple Silicon(arm64)。Intel Mac 上可从源码编译:GOOS=darwin GOARCH=amd64 go build zwcorsproxy.go

Linux

chmod +x zwcorsproxy-linux
./zwcorsproxy-linux
./zwcorsproxy-linux -port 9000

怎么用

启动后,代理会打印自己的地址。在任意跨域视频 URL 前加上它,就能在任何原本用原始 URL 的地方使用:

http://127.0.0.1:8000/?url=https://example.com/video.mp4
http://127.0.0.1:8000/?url=https://cdn.example.com/master.m3u8

放进 HTML <video> 标签:

<video src="http://127.0.0.1:8000/?url=https://cdn.example.com/video.mp4" controls></video>

配合 hls.js:

hls.loadSource('http://127.0.0.1:8000/?url=https://cdn.example.com/master.m3u8');

如果目标 URL 本身带 query 参数(如 ?token=abc),建议用 encodeURIComponent 整体编码,避免 & 被当成代理自身 query 串的一部分。

mp4 与 m3u8:各自怎么处理

内容 代理做什么 状态码
mp4 / 二进制流 流式 io.Copy 透明转发。Range/Content-Range/Accept-Ranges 和状态码原样复制。 200 / 206(原样)
m3u8 播放列表 读全文,把内部每个 URL 重写成代理的 base64 路径,再写回。 200(body 已变)

m3u8 重写是关键。如果代理只是原样返回播放列表文本,浏览器随后会直连原始 CDN 去取每个 .ts 分片——再次撞上同样的 CORS 错误。所以 ZWCorsProxy 把每一个引用(分片行、#EXT-X-KEYURI=#EXT-X-MEDIAURI=#EXT-X-MAP、master 变体等)都重写成 base64 路径:

http://127.0.0.1:8000/aHR0cHM6Ly9jZG4vc2VnbWVudC0wLnRz

浏览器请求这个路径时,代理把 base64 解码回原始 URL 再去取。整条 HLS 链路——master → 子 playlist → 分片——每一级都经代理,CORS 全程干净。

HTTPS(内嵌证书)

某些浏览器和播放器在 HTTPS 下表现更好(混合内容规则、安全上下文 API)。ZWCorsProxy 复用了与 ZWServe 相同的内嵌 30 年自签证书——绑定 127.0.0.1 + localhost,有效期 2026–2056。信任一次,两个工具都能跑 HTTPS。

# 导出证书到当前目录
./zwcorsproxy-win.exe -writecert
# → 产出 zwserver.crt / zwserver.key / zwserver.pem

# 以 HTTPS 启动
./zwcorsproxy-win.exe -https

zwserver.crt 装进系统信任库(Windows:certutil -addstore -f Root zwserver.crt;macOS:security add-trusted-cert …;Linux:拷到 CA 目录后跑 update-ca-certificates)。各平台安装脚本见 ZWServe 指南——证书完全相同。

与 ZWPlayer(及 M3U8Grab / ZWServe)搭配使用

ZWCorsProxy 是 zwplayer.com 流媒体工具家族的一员。它们覆盖三种不同场景:

工具 解决问题 什么时候用
ZWCorsProxy 跨域视频在线放不出来 想在浏览器里即时播放,不下载
M3U8Grab 想把跨域 m3u8 保存到本地离线 下载整条流(分片、密钥、字幕)本地播放
ZWServe 你的本地文件有 CORS 问题 给网页播放器提供带 CORS 的静态服务

搭配 ZWPlayer——一个功能完整的网页视频播放器——你可以把 ZWCorsProxy 的 URL 直接粘进播放器的源地址输入框,立刻播放任意跨域 mp4 或 m3u8,字幕、章节、播放列表功能都不受影响。

命令行参数

参数 默认值 说明
-port 8000 监听端口。
-host 127.0.0.1 绑定的本机 IP。必须是本机网卡实际存在的地址;0.0.0.0 被拒绝。用局域网 IP(如 192.168.1.50)可让其它设备访问。
-referer (空) 伪造发给上游的 Referer(防盗链场景);空则用目标自身 host。
-https false 用内嵌自签证书启用 HTTPS。
-cert (空) 自定义 TLS 证书路径(PEM);需配 -key
-key (空) 自定义 TLS 私钥路径(PEM);需配 -cert
-writecert false 把内嵌证书导出到当前目录(zwserver.crt/.key/.pem)后退出。
-log on 访问日志:on(默认)或 off
-h 显示帮助。

常用配方

zwcorsproxy                                   # 127.0.0.1:8000, HTTP
zwcorsproxy -port 9000
zwcorsproxy -host 192.168.1.50                # 绑局域网 IP(其它设备可访问)
zwcorsproxy -referer "https://example.com"    # 绕防盗链
zwcorsproxy -https                            # HTTPS(需先信任内嵌证书)
zwcorsproxy -log off                          # 安静模式(播放器 seek 会刷屏日志)

常见问题

为什么默认绑 127.0.0.1?能绑局域网 IP 吗?

CORS 代理是个很有威力的东西——任何能访问它的人都能让它代替自己去请求任意 URL。所以默认绑 127.0.0.1(仅回环)。如果你想让局域网里的其它设备(手机、平板)也能用这个代理,用 -host <你的局域网IP> 启动(如 -host 192.168.1.50)。-host 的值必须是本机网卡实际存在的 IP,而 0.0.0.0(全网卡)被刻意拒绝——绑定全网卡会让你的机器变成开放代理,局域网里任何人都能借你的 IP 去爬虫或隐藏来源。

我代理了一个 m3u8,但分片还是失败,为什么?

确保你是通过代理请求 m3u8?url=…/master.m3u8),而不是请求原始 URL。代理通过内容类型(Content-Type)或 #EXTM3U 前缀检测 m3u8,然后把分片 URL 重写成 base64 路径。如果你把播放列表文本复制出来直接请求分片,那些请求会绕过代理、撞上 CORS。

能用于非视频请求吗?

可以——它是一个带 CORS 头的通用 HTTP 反向代理。图片、JSON API、字体等都能用。但它是为视频优化的(Range 支持、m3u8 重写、长连接不超时)。非视频场景用通用工具可能更合适。

安全吗?SSRF 呢?

安全。除了绑回环,ZWCorsProxy 还会校验每一个目标:拒绝私网 IP 段(RFC1918)、回环、链路本地、云元数据地址(169.254.169.254)、IPv6 ULA(fc00::/7)以及非 HTTP 协议(file://ftp:// 等)。转发前还会剥离浏览器的 OriginCookie 头,所以你的登录 cookie 不会泄给视频源。

不会。转发上游请求前会剥离 Cookie 和 Origin 头。代理用一个标准浏览器 User-Agent 和一个 Referer(你用 -referer 指定的,或缺省用目标自身 host)来标识自己。

总结

ZWCorsProxy 是让跨域视频在浏览器播放最简单的方法:在 URL 前加上本地前缀,搞定。mp4 流透明转发,Range/拖动完整支持;m3u8 播放列表自动重写,整条 HLS 链路 CORS 干净。它是单个自包含二进制,绑 127.0.0.1 带 SSRF 防护,并复用 ZWServe 的 TLS 证书可选 HTTPS。

搭配 ZWPlayer 试试——粘进一个代理 URL,就能播放任意跨域视频,字幕、章节、播放列表俱全。想离线保存,配合 M3U8Grab;想给自己的本地文件加 CORS,用 ZWServe

— from zwplayer.com