Nginx实现FLV视频流代理转发:跨域与鉴权踩坑全记录

前端用 flv.js 播放 HTTP-FLV 视频流时,经常会遇到跨域、HTTPS 混合内容、鉴权等问题。本文记录了我用 Nginx 反向代理解决这些问题的完整过程,以及踩过的坑:HEAD 误判、GET 才触发 401、上游地址混淆等。

一、问题背景:为什么要做 FLV 代理?

前端用 flv.js 播放 HTTP-FLV 时,通常会遇到两个现实问题:

1. 跨域(CORS)

原始视频流地址来自另一个域名/IP,例如:

1
http://19.15.67.125/slvideo_SYY_172/hls/47c18e6792155981a28f3951977db417.flv?token=...

浏览器直接请求会被 CORS 拦截,导致无法播放。

2. HTTPS 页面混合内容(Mixed Content)

如果前端页面是 https://,而视频源站是 http://,浏览器会直接拦截或提示不安全。

最稳的方式是:让前端始终请求”同源/同协议”的代理地址,由 Nginx 去转发到源站。

为了解决这些问题,我选择用 Nginx 反向代理:前端请求 Nginx,本机/同域返回并加 CORS 头,Nginx 转发到真实源站。

二、先把关系搞清楚:三类地址最容易混淆

这次踩坑里最容易搞错的是:**哪个是”源站”,哪个是”Nginx 代理服务器”**。

类型 地址
Nginx 代理服务器(我的机器) http://10.144.32.219:18001
真实 FLV 源站(视频平台/摄像头出口) http://19.15.67.125
前端最终应该请求的地址 http://10.144.32.219:18001/video-proxy/...

一开始我误把 10.144.32.219 当成上游源站写进了 proxy_pass,导致逻辑变成”代理转发到自己”,怎么都不对。

经验结论

/api/video/play 返回的 data.httpflv 的 host 为准:它返回的是 19.15.67.125,那 Nginx 的 proxy_pass 就必须指向 19.15.67.125

三、一个很隐蔽的坑:curl -I 会误导你(HEAD ≠ GET)

我最开始用:

1
curl -I "http://19.15.67.125/xxx.flv?token=..."

结果看到 200 OK,还以为源站没问题。

但后来改用真正拉数据的方式:

1
curl -v --range 0-1023 --output NUL "http://19.15.67.125/xxx.flv?token=..."

马上暴露真实情况:401 Unauthorized

为什么会这样?

  • curl -I 发的是 HEAD 请求,只要响应头,不取 body
  • 很多流媒体/鉴权服务对 HEAD 的处理很”宽松”或直接返回空头;真正的权限校验是在 GET 才触发
  • 所以判定视频流是否可拉,必须用 GET(最好带 Range)测试

结论:不要用 HEAD 判断 FLV 是否可用,请用 GET + Range

四、核心方案:Nginx 反向代理配置

最终配置(固定上游 + 路径透传)

我选择在独立端口 18001 上单独开一个 server,并限定只匹配 /video-proxy/,避免误伤其它请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
server {
listen 18001;
server_name _;

# 仅匹配视频流代理路径,避免无关请求干扰
location /video-proxy/ {

# 处理 OPTIONS 预检请求(跨域必备)
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Range, If-Range, User-Agent, Content-Type' always;
add_header 'Access-Control-Max-Age' 3600 always;
add_header 'Content-Length' 0;
return 204;
}

# 转发到真实 FLV 源站(末尾 / 保证路径透传)
proxy_pass http://19.15.67.125/;
proxy_http_version 1.1;
proxy_set_header Host 19.15.67.125;

# 透传客户端信息(可选,但建议)
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# FLV 流媒体关键:Range/If-Range + 关闭缓冲 + 长超时
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

# CORS 响应头(建议 always,避免偶发错误没有跨域头)
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range, Accept-Ranges' always;

# 不缓存(按需)
add_header 'Cache-Control' 'no-cache, no-store, must-revalidate' always;
}
}

为什么 proxy_pass 末尾一定要有 /

写法 效果
proxy_pass http://19.15.67.125/; 会把 /video-proxy/ 前缀剥掉后透传到源站 ✅
proxy_pass http://19.15.67.125; 路径拼接规则会变,容易把 /video-proxy/ 一起带过去造成 404 ❌

这点是流媒体代理里最常见的”明明能连上但总 404”的坑。

五、前端拼接规则

原始地址

1
http://19.15.67.125/slvideo_SYY_172/hls/xxx.flv?token=xxx

前端最终请求(同源代理)

1
http://10.144.32.219:18001/video-proxy/slvideo_SYY_172/hls/xxx.flv?token=xxx

示例代码(核心思路是只取 pathname + search):

1
2
3
4
5
const originalFlv = data.httpflv; // http://19.15.67.125/xxx.flv?token=...
const url = new URL(originalFlv);
const proxyPath = url.pathname + url.search;
const flvUrl = `http://10.144.32.219:18001/video-proxy${proxyPath}`;
// or 用 window.location.origin(同域时更方便)

六、验证与排错

1) 语法检查并重载(Windows)

1
2
nginx.exe -t
nginx.exe -s reload

2) 端口监听确认

1
netstat -ano | findstr :18001

3) 用 GET + Range 测试代理

1
curl -v --range 0-1023 --output NUL "http://10.144.32.219:18001/video-proxy/slvideo_SYY_172/hls/xxx.flv?token=xxx"

期望:200206 Partial Content不是 401/403/502/504

4) 如果出现 401:这是鉴权问题,不是跨域问题

这次对话里最关键的真相是:源站对 curl 的 GET 请求返回 401 Unauthorized

这说明:

  • token 可能很快过期(几秒到几分钟)
  • 或者源站除了 token 还校验 Referer/Cookie/Authorization/User-Agent
  • 代理配置再完美,鉴权不过依旧会 401

可选:透传常见鉴权 header

1
2
3
4
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header Authorization $http_authorization;
proxy_set_header User-Agent $http_user_agent;

安全提醒:透传 Cookie/Authorization 之前最好加访问控制(白名单/内网),避免变成开放代理。

七、Windows 部署补充

Windows 下 Nginx 放哪都能跑,但会影响:

  • include mime.types; 这类相对路径能否找到
  • logs/ 是否有写权限
  • 你是否能稳定重载/开机自启

推荐固定目录:C:\nginx\

用”明确前缀和配置文件”的方式启动:

1
C:\nginx\nginx.exe -p C:\nginx\ -c conf\nginx.conf

重载同理:

1
C:\nginx\nginx.exe -p C:\nginx\ -c conf\nginx.conf -s reload

八、踩坑总结

解决方案
host 搞错 以 API 返回的 httpflv host 为准
HEAD 验证误导 必须用 GET + Range 测试
401 当成跨域问题 401 是鉴权问题,代理不能绕过权限
Windows Nginx 路径混乱 固定 -p-c 参数启动
端口不通 Windows 防火墙/安全组都要开放

结语

通过 Nginx 反向代理,我们成功解决了 FLV 视频流的跨域和 HTTPS 混合内容问题。关键在于:搞清楚源站地址、用正确的方式验证、理解 401 是鉴权而非跨域问题。希望这篇踩坑记录能帮到你!


💡 提示:如果需要在 HTTPS 环境下使用,只需将代理 server 配到 443 端口并配置 SSL 证书即可。