使用 302 时 Nginx 负载均衡器错误
Posted
技术标签:
【中文标题】使用 302 时 Nginx 负载均衡器错误【英文标题】:Nginx load balancer error when 302 is used 【发布时间】:2017-06-10 22:37:06 【问题描述】:我有一个 nginx 容器用作负载平衡器,用于基于流式 DASH 的服务。还有 3 个 VM 用作上游服务器。 这是 nginx 配置文件:
upstream cdn-audio
server 192.168.99.103:9500;
server 192.168.99.104:9500;
server 192.168.99.105:9500;
upstream cdn-video
server 192.168.99.103:9500;
server 192.168.99.104:9500;
server 192.168.99.105:9500;
server
listen 80;
server_name 172.17.0.1;
access_log /var/log/nginx/acces.log main;
location = /LynyrdSkynyrdFreebirdAudio.mp4
# proxy_pass http://192.168.99.103:9500;
# proxy_pass http://cdn-audio/LynyrdSkynyrdFreebirdAudio.mp4;
add_header X-Upstream $upstream_addr;
add_header Host $host;
if ($request_method = OPTIONS)
add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Headers "Authorization,Range";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
add_header Host $host;
return 200;
return 302 $scheme://cdn-audio/LynyrdSkynyrdFreebirdAudio.mp4;
location = /LynyrdSkynyrdFreebirdVideo.mp4
add_header X-Upstream $upstream_addr;
# proxy_pass http://cdn-audio/LynyrdSkynyrdFreebirdVideo.mp4;
add_header Host $host;
if ($request_method = OPTIONS)
add_header Access-Control-Allow-Origin '*' ;
add_header Access-Control-Allow-Headers "Authorization,Range";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
add_header Host $host;
return 200;
# proxy_pass http://cdn-video$request_uri;
# proxy_pass http://192.168.99.103:9500;
return 302 $scheme://cdn-video/LynyrdSkynyrdFreebirdVideo.mp4;
# add_header X-Upstream $upstream_addr;
从托管在另一个容器(前端容器)中的 html 页面,首先有一个 HTTP OPTIONS 请求到 :/LynyrdSkynyrdFreebirdAudio.mp4 和 :/LynyrdSkynyrdFreebirdVideo.mp4,因为跨站点来源。 然后响应头显示在配置代码中。
然后,当我尝试将请求重定向到我的三个上游服务器之一时,出现错误:
XMLHttpRequest 无法加载 http://localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4。重定向自 'http://localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4' 到 'http://cdn-video/LynyrdSkynyrdFreebirdVideo.mp4' 已被阻止 CORS 政策:请求需要预检,这是不允许的 遵循跨域重定向。 XMLHttpRequest 无法加载 http://localhost:9200/LynyrdSkynyrdFreebirdAudio.mp4。重定向自 'http://localhost:9200/LynyrdSkynyrdFreebirdAudio.mp4' 到 'http://cdn-audio/LynyrdSkynyrdFreebirdAudio.mp4' 已被阻止 CORS 政策:请求需要预检,这是不允许的 遵循跨域重定向。请注意我做了
curl -I -X OPTIONS http://192.168.99.103:9500/LynyrdSkynyrdFreebirdAudio.mp4
这是回复:
HTTP/1.1 200 OK
Server: nginx/1.11.8
Date: Wed, 25 Jan 2017 16:31:28 GMT
Content-Length: 0
Connection: keep-alive
Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Range
你能帮我解决这个问题吗?
【问题讨论】:
你明白为什么你的浏览器会发送 OPTIONS 预检请求而不是直接发送实际请求吗?这通常仅在您向请求添加自定义标头或将请求的内容类型设置为特定值时才会发生。您可能只需对您的请求进行一些调整即可避免 OPTIONS 预检(例如,从中删除可能添加的任何不必要的标头)。 这是我的架构:我在一个容器中有一个前端 html+js;负载均衡器容器; N VM 作为 CDN。首先,我用前端 html 指向 l.b:这会导致 OPTIONS 预检请求,因为这是一个跨站点源请求。如果在 l.b. 中,我使用 proxy_pass 指令(返回 302 等),在第一个 OPTIONS 请求之后,我可以通过 HTTP GET 访问内容。如果我使用返回 302 等,在这个 HTTP 选项(响应正确)之后,我从浏览器的网络控制台看到很多 GET 和 302 响应......以及我在上面发布的错误。我认为这个错误是由返回 302 引起的。 这是一个跨站点请求的事实并不是导致发送 OPTIONS 的原因。 Lots of cross-site requests do not cause an OPTIONS request。触发发送 OPTIONS 的是您发送的特定请求的特定性质:如果它包含定义为 CORS-safelisted request-headers 的标题以外的标题,则只有这样才会发送 OPTIONS。因此,您可以通过从请求中删除一些标头来避免 OPTIONS。 【参考方案1】:您的 nginx 配置正在向浏览器返回 302。
换句话说,您正在尝试将请求从“localhost”重定向到“cdn-video”(除非您已配置本地 DNS 或主机文件映射)在您的浏览器中无法解析。
您还应该将 CORS 方法标头添加到您的 nginx 配置中
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
我建议将您的 nginx 配置简化为(未经测试):
upstream cdn-audio
least_conn;
server 192.168.99.103:9500;
server 192.168.99.104:9500;
server 192.168.99.105:9500;
upstream cdn-video
least_conn;
server 192.168.99.103:9500;
server 192.168.99.104:9500;
server 192.168.99.105:9500;
server
listen 80;
server_name 172.17.0.1;
access_log /var/log/nginx/acces.log main;
location /audio/
if ($request_method = OPTIONS)
add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers "Authorization,Range";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
add_header Host $host;
return 200;
proxy_pass http://cdn-audio; # expects the audio files to be in a "audio" folder on the upstream box
add_header X-Upstream $upstream_addr;
add_header Host $host;
location /video/
if ($request_method = OPTIONS)
add_header Access-Control-Allow-Origin '*' ;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers "Authorization,Range";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
add_header Host $host;
return 200;
proxy_pass http://cdn-video; # expects the video files to be in a "video" folder on the upstream box
add_header X-Upstream $upstream_addr;
add_header Host $host;
【讨论】:
感谢您的回答,@justcompile。我已经添加了这一行,并且还允许 origin * 。支持 CORS。但仍然是同样的错误。 我不想要proxy_pass,而是使用302 临时移动的重定向方法。这是因为此负载均衡器具有构成 CDN 的上游服务器,因此使用 proxy_pass 指令可能会成为瓶颈。 瓶颈是否意味着 1 个上游服务器可能会比另一个服务器获得更多的请求?您可以将“least_conn”指令添加到上游定义中,以便 nginx 将流量发送到具有最少连接数的服务器。我将修改示例(无论我是否理解正确):) 我现在的瓶颈是负载均衡器,因为:如果这些内容有 100、1000 个 http 请求,负载均衡器就是瓶颈。我的目标是使用重定向方法配置负载均衡器:例如,如果有 200 个浏览器指向负载均衡器 (l.b.) 内容,则负载均衡器承受着巨大的负载。为了避免这个问题,我想使用重定向方法:一旦浏览器指向 lb,它会告诉浏览器“重定向到上游 192.168.99.103:9500 或 192.168.99.104:9500”;然后浏览器获取资源到 192.168.99.103:9500,例如。 我明白了。那么我的观点是关于浏览器不知道什么是“cdn-video”是相关的。还要确保您的服务器也返回 cors 标头,因为一旦您重定向,这些标头将需要存在于来自重定向位置的响应中【参考方案2】:@sideshowbarker 这些是请求和响应标头,以防 proxy_pass 和重定向 302。
header options + get chunk with proxy pass:
OPTIONS
General
Request URL:http://localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4
Request Method:OPTIONS
Status Code:200 OK
Remote Address:127.0.0.1:9200
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Range
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:*
Connection:keep-alive
Content-Length:0
Content-Length:0
Content-Type:text/plain
Content-Type:video/mp4
Date:Thu, 26 Jan 2017 08:41:52 GMT
Host:localhost
Server:nginx/1.11.6
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers:range
Access-Control-Request-Method:GET
Connection:keep-alive
Host:localhost:9200
Origin:http://localhost:8400
Referer:http://localhost:8400/shaka-player-master/demo/homepage.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
GET
General
Request URL:http://localhost:9200/LynyrdSkynyrdFreebirdAudio.mp4
Request Method:GET
Status Code:206 Partial Content
Remote Address:127.0.0.1:9200
Response Headers
view source
Access-Control-Allow-Headers:Range
Access-Control-Allow-Origin:*
Connection:keep-alive
Content-Length:692
Content-Range:bytes 1040-1731/6797033
Content-Type:video/mp4
Date:Thu, 26 Jan 2017 08:41:52 GMT
ETag:W/"6797033-1484728792000"
Host:localhost
Last-Modified:Wed, 18 Jan 2017 08:39:52 GMT
Server:nginx/1.11.6
X-Proxy-Cache:MISS
X-Upstream:192.168.99.103:9500
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Host:localhost:9200
Origin:http://localhost:8400
Range:bytes=1040-1731
Referer:http://localhost:8400/shaka-player-master/demo/homepage.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
header options and get chunk with redirect:
OPTIONS:
General
Request URL:http://localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4
Request Method:OPTIONS
Status Code:200 OK
Remote Address:127.0.0.1:9200
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Range
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:*
Connection:keep-alive
Content-Length:0
Content-Length:0
Content-Type:text/plain
Content-Type:video/mp4
Date:Thu, 26 Jan 2017 08:52:22 GMT
Host:localhost
Server:nginx/1.11.6
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers:range
Access-Control-Request-Method:GET
Connection:keep-alive
Host:localhost:9200
Origin:http://localhost:8400
Referer:http://localhost:8400/shaka-player-master/demo/homepage.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
GET
General
Request URL:http://localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4
Request Method:GET
Status Code:302 Moved Temporarily
Remote Address:127.0.0.1:9200
Response Headers
view source
Connection:keep-alive
Content-Length:161
Content-Type:text/html
Date:Thu, 26 Jan 2017 08:52:22 GMT
Host:localhost
Location:http://cdn-video/LynyrdSkynyrdFreebirdVideo.mp4
Server:nginx/1.11.6
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Host:localhost:9200
Origin:http://localhost:8400
Range:bytes=1136-1767
Referer:http://localhost:8400/shaka-player-master/demo/homepage.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Initiator = http://localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4 ; type= xhr
SECOND GET:
General
Request URL:http://localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4
Request Method:GET
Status Code:302 Moved Temporarily
Remote Address:127.0.0.1:9200
Response Headers
view source
Connection:keep-alive
Content-Length:161
Content-Type:text/html
Date:Thu, 26 Jan 2017 08:52:22 GMT
Host:localhost
Location:http://cdn-video/LynyrdSkynyrdFreebirdVideo.mp4
Server:nginx/1.11.6
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Host:localhost:9200
Origin:http://localhost:8400
Range:bytes=1136-1767
Referer:http://localhost:8400/shaka-player-master/demo/homepage.html
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Initiator = "other"; type= text/html.
【讨论】:
【参考方案3】:使用谷歌金丝雀解决。
使用金丝雀,如果我将内容直接重定向到我的三个上游服务器之一,它就可以工作。 如果我重定向到上游名称(即 cdn-audio(或视频)),浏览器将无法解析名称。
我听说过用于 nginx 的 lua-upstream-module,有人可以帮帮我吗?
【讨论】:
以上是关于使用 302 时 Nginx 负载均衡器错误的主要内容,如果未能解决你的问题,请参考以下文章