這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)nginx代理出現(xiàn)302如何解決,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
目前累計(jì)服務(wù)客戶上1000+,積累了豐富的產(chǎn)品開發(fā)及服務(wù)經(jīng)驗(yàn)。以網(wǎng)站設(shè)計(jì)水平和技術(shù)實(shí)力,樹立企業(yè)形象,為客戶提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、網(wǎng)站策劃、網(wǎng)頁設(shè)計(jì)、網(wǎng)絡(luò)營銷、VI設(shè)計(jì)、網(wǎng)站改版、漏洞修補(bǔ)等服務(wù)。成都創(chuàng)新互聯(lián)公司始終以務(wù)實(shí)、誠信為根本,不斷創(chuàng)新和提高建站品質(zhì),通過對(duì)領(lǐng)先技術(shù)的掌握、對(duì)創(chuàng)意設(shè)計(jì)的研究、對(duì)客戶形象的視覺傳遞、對(duì)應(yīng)用系統(tǒng)的結(jié)合,為客戶提供更好的一站式互聯(lián)網(wǎng)解決方案,攜手廣大客戶,共同發(fā)展進(jìn)步。
用proxy_intercept_errors和recursive_error_pages代理多次302
302是HTTP協(xié)議中的一個(gè)經(jīng)常被使用狀態(tài)碼,是多種重定向方式的一種,其語義經(jīng)常被解釋為“Moved Temporarily”。這里順帶提一下,現(xiàn)實(shí)中用到的302多為誤用(與303,307混用),在HTTP/1.1中,它的語義為“Found”.
302有時(shí)候很明顯,有時(shí)候又比較隱蔽。最簡單的情況,是當(dāng)我們?cè)跒g覽器中輸入一個(gè)網(wǎng)址A,然后瀏覽器地址欄會(huì)自動(dòng)跳到B,進(jìn)而打開一個(gè)網(wǎng)頁,這種情況就很可能是302。
比較隱蔽的情況經(jīng)常發(fā)生在嵌入到網(wǎng)頁的播放器中。例如,當(dāng)你打開一個(gè)優(yōu)酷視頻播放頁面時(shí),抓包觀察一下就會(huì)經(jīng)常發(fā)現(xiàn)302的影子。但由于這些url并不是直接在瀏覽器中打開的,所以在瀏覽器的地址欄看不到變化,當(dāng)然,如果將這些具體的url特意挑出來復(fù)制到瀏覽器地址欄里,還是可以觀察到的。
上一段提到了優(yōu)酷。其實(shí)現(xiàn)在多數(shù)在線視頻網(wǎng)站都會(huì)用到302,原因很簡單,視頻網(wǎng)站流量一般較大,都會(huì)用到cdn,區(qū)別只在于是用自建CDN還是商業(yè)CDN。而由于302的重定向語義(再重復(fù)一遍,302的語義廣泛的被誤用,在使用302的時(shí)候,我們很可能應(yīng)該使用303或307,但后面都不再糾結(jié)這一點(diǎn)),可以與CDN中的調(diào)度很好的結(jié)合起來。
我們來看一個(gè)例子,打開一個(gè)網(wǎng)易視頻播放頁面,抓一下包,找到302狀態(tài)的那個(gè)url。例如:
http://flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4
我們把它復(fù)制到瀏覽器地址欄中,會(huì)發(fā)現(xiàn)地址欄迅速的變?yōu)榱肆硗庖粋€(gè)url,這個(gè)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工具會(huì)更清楚的看到整個(gè)過程:
?
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í)將這個(gè)例子放在一邊,再來說說另一個(gè)重要的術(shù)語:proxy.我們通常會(huì)戲稱,某些領(lǐng)導(dǎo)是302類型的,某些領(lǐng)導(dǎo)是proxy類型的。302類型的領(lǐng)導(dǎo),一件事情經(jīng)過他的手,會(huì)迅速的轉(zhuǎn)給他人,而proxy類型的領(lǐng)導(dǎo)則會(huì)參與到事情中來,甚至把事情全部做完。
回到上面的例子,如果訪問一個(gè)url中途會(huì)有多個(gè)302,那如果需要用Nginx設(shè)計(jì)一個(gè)proxy,來隱藏掉中間所有的這些302,該怎么做呢?
1.原始Proxy
我們知道,Nginx本身就是一個(gè)優(yōu)秀的代理服務(wù)器。因此,首先我們來架設(shè)一個(gè)Nginx正向代理,服務(wù)器IP為192.168.109.128(我的一個(gè)測(cè)試虛擬機(jī))。
初始配置簡化如下:
?
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;
}
}
|
實(shí)現(xiàn)的功能是,當(dāng)使用
http://192.168.109.128/xxxxxx
訪問該代理時(shí),會(huì)proxy到xxxxxx所代表的真實(shí)服務(wù)器。
測(cè)試結(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ū)別。訪問過程為,當(dāng)訪問
http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4
時(shí),Nginx會(huì)將該請(qǐng)求proxy到
http://flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4
而后者馬上就會(huì)返回一個(gè)302,所以Nginx作為proxy,將該302傳回到客戶端,客戶端重新發(fā)起請(qǐng)求,進(jìn)而重復(fù)之前的多次302.這里說明一個(gè)問題,一旦Nginx的proxy的后端返回302后,客戶端即與Nginx這個(gè)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ū)別在于,使用了一個(gè)error_page,目的是當(dāng)發(fā)現(xiàn)proxy的后端返回302時(shí),則用這個(gè)302的目的location繼續(xù)proxy,而不是直接返回給客戶端。并且這個(gè)邏輯里面包含著遞歸的意思,一路跟蹤302,直到最終返回200的那個(gè)地址。測(cè)試結(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
|
可見,本次修改仍然沒有成功!
為什么呢?分析一下,我們?cè)贎error_page_302這個(gè)location里已經(jīng)加了一個(gè)頭部打印語句,可是在測(cè)試中,該頭部并沒有打出來,可見流程并沒有進(jìn)入到@error_page_302這個(gè)location。
原因在于
?
1 | error_page 302 = @error_page_302;
|
error_page默認(rèn)是本次處理的返回碼。作為proxy,本次處理,只要轉(zhuǎn)發(fā)上游服務(wù)器的響應(yīng)成功,應(yīng)該狀態(tài)碼都是200.即,我們真正需要檢查的,是proxy的后端服務(wù)器返回的狀態(tài)碼,而不是proxy本身返回的狀態(tài)碼。查一下Nginx的wiki,proxy_intercept_errors指令正是干這個(gè)的:
?
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ū)別僅僅在于增加了一個(gè)proxy_intercept_errors指令。測(cè)試結(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
|
這次更神奇了,直接返回一個(gè)302狀態(tài)完事,也不繼續(xù)跳轉(zhuǎn)了。
問題出在,雖然第一次302,請(qǐng)求成功的進(jìn)入到@error_page_302,但后續(xù)的error_page指令卻沒起作用。也就是說,error_page只檢查了第一次后端返回的狀態(tài)碼,而沒有繼續(xù)檢查后續(xù)的后端狀態(tài)碼。
查一下資料,這個(gè)時(shí)候,另一個(gè)指令 recursive_error_pages就派上用場(chǎng)了。
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這條指令。測(cè)試結(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了。此時(shí),Nginx才真正起到了一個(gè)Proxy的功能,隱藏了一個(gè)請(qǐng)求原本的多個(gè)302鏈路,只返回客戶端一個(gè)最終結(jié)果。
上述就是小編為大家分享的nginx代理出現(xiàn)302如何解決了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
分享名稱:nginx代理出現(xiàn)302如何解決
分享路徑:
http://weahome.cn/article/joedho.html