Nginx load balancer error when 302 is used

2019-09-16 08:18发布

问题:

I've an nginx container used as load balancer, for a streaming DASH-based service.There are also 3 VM used as upstream servers. This is nginx config file:

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;

        }

   }

From an html page hosted in another container ( a frontend container), first there is a HTTP OPTIONS request to :/LynyrdSkynyrdFreebirdAudio.mp4 and :/LynyrdSkynyrdFreebirdVideo.mp4, because of cross site origin. Then the response header is shown in the config code.

Then, when i try to redirect request to one of my three upstream server, there is an error:

  • XMLHttpRequest cannot load http: // localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4. Redirect from 'http: // localhost:9200/LynyrdSkynyrdFreebirdVideo.mp4' to 'http: // cdn-video/LynyrdSkynyrdFreebirdVideo.mp4' has been blocked by CORS policy: Request requires preflight, which is disallowed to follow cross-origin redirect.
  • XMLHttpRequest cannot load http: // localhost:9200/LynyrdSkynyrdFreebirdAudio.mp4. Redirect from 'http: // localhost:9200/LynyrdSkynyrdFreebirdAudio.mp4' to 'http: // cdn-audio/LynyrdSkynyrdFreebirdAudio.mp4' has been blocked by CORS policy: Request requires preflight, which is disallowed to follow cross-origin redirect.

Please note that i made

curl -I -X OPTIONS http://192.168.99.103:9500/LynyrdSkynyrdFreebirdAudio.mp4

This is response:

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

Can you help me to solve this problem?

回答1:

Your nginx configuration is returning a 302 to the browser.

In other words, you're trying to redirect requests from "localhost" to "cdn-video" which (unless you've configured local DNS or hosts file mapping) won't resolve in your browser.

You should also add the CORS methods header to your nginx config

add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

I'd suggest simplifying your nginx config to something along the lines of (untested):

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;
  }
}


回答2:

@sideshowbarker These are the request and response header, in case of proxy_pass and redirect 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:

Resolved using google canary.

With canary, it works if i redirect content directly to one of my three upstream server. If i redirect to upstream name (i.e. cdn-audio(or video)) the browser cannot resolve name.

I've heard about lua-upstream-module for nginx, can someone help me?