溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

nginx代理出現(xiàn)302如何解決

發(fā)布時間:2021-03-09 15:41:03 來源:億速云 閱讀:3208 作者:Leah 欄目:服務(wù)器

這期內(nèi)容當中小編將會給大家?guī)碛嘘P(guān)nginx代理出現(xiàn)302如何解決,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

用proxy_intercept_errors和recursive_error_pages代理多次302

302是HTTP協(xié)議中的一個經(jīng)常被使用狀態(tài)碼,是多種重定向方式的一種,其語義經(jīng)常被解釋為“Moved Temporarily”。這里順帶提一下,現(xiàn)實中用到的302多為誤用(與303,307混用),在HTTP/1.1中,它的語義為“Found”.

302有時候很明顯,有時候又比較隱蔽。最簡單的情況,是當我們在瀏覽器中輸入一個網(wǎng)址A,然后瀏覽器地址欄會自動跳到B,進而打開一個網(wǎng)頁,這種情況就很可能是302。

比較隱蔽的情況經(jīng)常發(fā)生在嵌入到網(wǎng)頁的播放器中。例如,當你打開一個優(yōu)酷視頻播放頁面時,抓包觀察一下就會經(jīng)常發(fā)現(xiàn)302的影子。但由于這些url并不是直接在瀏覽器中打開的,所以在瀏覽器的地址欄看不到變化,當然,如果將這些具體的url特意挑出來復制到瀏覽器地址欄里,還是可以觀察到的。

上一段提到了優(yōu)酷。其實現(xiàn)在多數(shù)在線視頻網(wǎng)站都會用到302,原因很簡單,視頻網(wǎng)站流量一般較大,都會用到CDN,區(qū)別只在于是用自建CDN還是商業(yè)CDN。而由于302的重定向語義(再重復一遍,302的語義廣泛的被誤用,在使用302的時候,我們很可能應(yīng)該使用303或307,但后面都不再糾結(jié)這一點),可以與CDN中的調(diào)度很好的結(jié)合起來。

我們來看一個例子,打開一個網(wǎng)易視頻播放頁面,抓一下包,找到302狀態(tài)的那個url。例如:

http://flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

我們把它復制到瀏覽器地址欄中,會發(fā)現(xiàn)地址欄迅速的變?yōu)榱肆硗庖粋€url,這個Url是不定的,有可能為:

http://14.18.140.83/f6c00af500000000-1408987545-236096587/data6/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

用curl工具會更清楚的看到整個過程:

?

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

curl -I "http://flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L

HTTP/1.1 302 Moved Temporarily

Server: nginx

Date: Mon, 25 Aug 2014 14:49:43 GMT

Content-Type: text/html

Content-Length: 154

Connection: keep-alive

NG: CCN-SW-1-5L2

X-Mod-Name: GSLB/3.1.0

Location: http://119.134.254.9/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

 

HTTP/1.1 302 Moved Temporarily

Server: nginx

Date: Mon, 25 Aug 2014 14:49:41 GMT

Content-Type: text/html

Content-Length: 154

Connection: keep-alive

X-Mod-Name: Mvod-Server/4.3.3

Location: http://119.134.254.7/cc89fdac00000000-1408983581-2095617481/data4/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

NG: CHN-SW-1-3Y1

 

HTTP/1.1 200 OK

Server: nginx

Date: Mon, 25 Aug 2014 14:49:41 GMT

Content-Type: video/mp4

Content-Length: 3706468

Last-Modified: Mon, 25 Aug 2014 00:23:50 GMT

Connection: keep-alive

Cache-Control: no-cache

ETag: "53fa8216-388e64"

NG: CHN-SW-1-3g6

X-Mod-Name: Mvod-Server/4.3.3

Accept-Ranges: bytes

可以看到,這中間經(jīng)歷了兩次302。

先暫時將這個例子放在一邊,再來說說另一個重要的術(shù)語:proxy.我們通常會戲稱,某些領(lǐng)導是302類型的,某些領(lǐng)導是proxy類型的。302類型的領(lǐng)導,一件事情經(jīng)過他的手,會迅速的轉(zhuǎn)給他人,而proxy類型的領(lǐng)導則會參與到事情中來,甚至把事情全部做完。

回到上面的例子,如果訪問一個url中途會有多個302,那如果需要用Nginx設(shè)計一個proxy,來隱藏掉中間所有的這些302,該怎么做呢?

1.原始Proxy

我們知道,Nginx本身就是一個優(yōu)秀的代理服務(wù)器。因此,首先我們來架設(shè)一個Nginx正向代理,服務(wù)器IP為192.168.109.128(我的一個測試虛擬機)。

初始配置簡化如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

server {

    listen 80;

    location / {

        rewrite_by_lua '

            ngx.exec("/proxy-to" .. ngx.var.request_uri)

        ';

    }

 

    location ~ /proxy-to/([^/]+)(.*) {

        proxy_pass http://$1$2$is_args$query_string;

 

    }

}

實現(xiàn)的功能是,當使用

http://192.168.109.128/xxxxxx

訪問該代理時,會proxy到xxxxxx所代表的真實服務(wù)器。

測試結(jié)果如下:

?

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

curl -I "http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L

HTTP/1.1 302 Moved Temporarily

Server: nginx/1.4.6

Date: Mon, 25 Aug 2014 14:50:54 GMT

Content-Type: text/html

Content-Length: 154

Connection: keep-alive

NG: CCN-SW-1-5L2

X-Mod-Name: GSLB/3.1.0

Location: http://183.61.140.24/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

 

HTTP/1.1 302 Moved Temporarily

Server: nginx

Date: Mon, 25 Aug 2014 14:50:55 GMT

Content-Type: text/html

Content-Length: 154

Connection: keep-alive

X-Mod-Name: Mvod-Server/4.3.3

Location: http://183.61.140.20/540966e500000000-1408983655-236096587/data1/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

NG: CHN-ZJ-4-3M4

 

HTTP/1.1 200 OK

Server: nginx

Date: Mon, 25 Aug 2014 14:50:55 GMT

Content-Type: video/mp4

Content-Length: 3706468

Last-Modified: Mon, 25 Aug 2014 00:31:03 GMT

Connection: keep-alive

Cache-Control: no-cache

ETag: "53fa83c7-388e64"

NG: CHN-ZJ-4-3M4

X-Mod-Name: Mvod-Server/4.3.3

Accept-Ranges: bytes

可見,雖然使用proxy,但過程與原始訪問沒有什么區(qū)別。訪問過程為,當訪問

http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

時,Nginx會將該請求proxy到

http://flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

而后者馬上就會返回一個302,所以Nginx作為proxy,將該302傳回到客戶端,客戶端重新發(fā)起請求,進而重復之前的多次302.這里說明一個問題,一旦Nginx的proxy的后端返回302后,客戶端即與Nginx這個proxy脫離關(guān)系了,Nginx無法起到完整的代理的作用。

2. 第1次修改

將配置文件修改為:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

server {

    listen 80;

    location / {

        rewrite_by_lua '

            ngx.exec("/proxy-to" .. ngx.var.request_uri)

        ';

    }

 

    location ~ /proxy-to/([^/]+)(.*) {

        proxy_pass http://$1$2$is_args$query_string;

        error_page 302 = @error_page_302;

 

    }

    location @error_page_302 {

        rewrite_by_lua '

            local _, _, upstream_http_location = string.find(ngx.var.upstream_http_location, "^http:/(.*)$")

            ngx.header["zzzz"] = "/proxy-to" .. upstream_http_location

            ngx.exec("/proxy-to" .. upstream_http_location);

        ';

 

    }

}

與上面的區(qū)別在于,使用了一個error_page,目的是當發(fā)現(xiàn)proxy的后端返回302時,則用這個302的目的location繼續(xù)proxy,而不是直接返回給客戶端。并且這個邏輯里面包含著遞歸的意思,一路跟蹤302,直到最終返回200的那個地址。測試結(jié)果如下:

?

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

curl -I "http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L

HTTP/1.1 302 Moved Temporarily

Server: nginx/1.4.6

Date: Mon, 25 Aug 2014 15:01:17 GMT

Content-Type: text/html

Content-Length: 154

Connection: keep-alive

NG: CCN-SW-1-5L2

X-Mod-Name: GSLB/3.1.0

Location: http://183.61.140.24/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

 

HTTP/1.1 302 Moved Temporarily

Server: nginx

Date: Mon, 25 Aug 2014 15:01:17 GMT

Content-Type: text/html

Content-Length: 154

Connection: keep-alive

X-Mod-Name: Mvod-Server/4.3.3

Location: http://183.61.140.20/a90a952900000000-1408984277-236096587/data1/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

NG: CHN-ZJ-4-3M4

 

HTTP/1.1 200 OK

Server: nginx

Date: Mon, 25 Aug 2014 15:01:17 GMT

Content-Type: video/mp4

Content-Length: 3706468

Last-Modified: Mon, 25 Aug 2014 00:31:03 GMT

Connection: keep-alive

Cache-Control: no-cache

ETag: "53fa83c7-388e64"

NG: CHN-ZJ-4-3M4

X-Mod-Name: Mvod-Server/4.3.3

Accept-Ranges: bytes

可見,本次修改仍然沒有成功!

為什么呢?分析一下,我們在@error_page_302這個location里已經(jīng)加了一個頭部打印語句,可是在測試中,該頭部并沒有打出來,可見流程并沒有進入到@error_page_302這個location。

原因在于

?

1

error_page 302 = @error_page_302;

error_page默認是本次處理的返回碼。作為proxy,本次處理,只要轉(zhuǎn)發(fā)上游服務(wù)器的響應(yīng)成功,應(yīng)該狀態(tài)碼都是200.即,我們真正需要檢查的,是proxy的后端服務(wù)器返回的狀態(tài)碼,而不是proxy本身返回的狀態(tài)碼。查一下Nginx的wiki,proxy_intercept_errors指令正是干這個的:

?

1

2

3

4

5

Syntax: proxy_intercept_errors on | off;

Default: 

proxy_intercept_errors off;

Context:  http, server, location

Determines whether proxied responses with codes greater than or equal to 300 should be passed to a client or be redirected to nginx for processing with the error_page directive.

3. 第二次修改

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

server {

    listen 80;

    proxy_intercept_errors on;

    location / {

        rewrite_by_lua '

            ngx.exec("/proxy-to" .. ngx.var.request_uri)

        ';

    }

    location ~ /proxy-to/([^/]+)(.*) {

        proxy_pass http://$1$2$is_args$query_string;

        error_page 302 = @error_page_302;

 

    }

    location @error_page_302 {

        rewrite_by_lua '

            local _, _, upstream_http_location = string.find(ngx.var.upstream_http_location, "^http:/(.*)$")

            ngx.header["zzzz"] = "/proxy-to" .. upstream_http_location

            ngx.exec("/proxy-to" .. upstream_http_location);

        ';

    }

}

與上一次修改相比,區(qū)別僅僅在于增加了一個proxy_intercept_errors指令。測試結(jié)果如下:

?

1

2

3

4

5

6

7

8

curl -I "http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L

HTTP/1.1 302 Moved Temporarily

Server: nginx/1.4.6

Date: Mon, 25 Aug 2014 15:05:54 GMT

Content-Type: text/html

Content-Length: 160

Connection: keep-alive

zzzz: /proxy-to/183.61.140.24/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

這次更神奇了,直接返回一個302狀態(tài)完事,也不繼續(xù)跳轉(zhuǎn)了。

問題出在,雖然第一次302,請求成功的進入到@error_page_302,但后續(xù)的error_page指令卻沒起作用。也就是說,error_page只檢查了第一次后端返回的狀態(tài)碼,而沒有繼續(xù)檢查后續(xù)的后端狀態(tài)碼。

查一下資料,這個時候,另一個指令 recursive_error_pages就派上用場了。

4. 第3次修改

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

server {

    listen 80;

    proxy_intercept_errors on;

    recursive_error_pages on;

    location / {

        rewrite_by_lua '

            ngx.exec("/proxy-to" .. ngx.var.request_uri)

        ';

    }

    location ~ /proxy-to/([^/]+)(.*) {

        proxy_pass http://$1$2$is_args$query_string;

        error_page 302 = @error_page_302;

 

    }

    location @error_page_302 {

        rewrite_by_lua '

            local _, _, upstream_http_location = string.find(ngx.var.upstream_http_location, "^http:/(.*)$")

            ngx.header["zzzz"] = "/proxy-to" .. upstream_http_location

            ngx.exec("/proxy-to" .. upstream_http_location);

        ';

    }

}

與上一次相比,僅僅增加了recursive_error_pages on這條指令。測試結(jié)果如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

curl -I "http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L

HTTP/1.1 200 OK

Server: nginx/1.4.6

Date: Mon, 25 Aug 2014 15:09:04 GMT

Content-Type: video/mp4

Content-Length: 3706468

Connection: keep-alive

zzzz: /proxy-to/14.18.140.83/f48bad0100000000-1408984745-236096587/data6/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

Last-Modified: Mon, 25 Aug 2014 00:21:07 GMT

Cache-Control: no-cache

ETag: "53fa8173-388e64"

NG: CHN-MM-4-3FE

X-Mod-Name: Mvod-Server/4.3.3

Accept-Ranges: bytes

可見,Nginx終于成功的返回200了。此時,Nginx才真正起到了一個Proxy的功能,隱藏了一個請求原本的多個302鏈路,只返回客戶端一個最終結(jié)果。

上述就是小編為大家分享的nginx代理出現(xiàn)302如何解決了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)
推薦閱讀:
  1. nginx代理
  2. Nginx代理tomcat

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI