Openresty 反向代理返回非200進行retry到自定義upstream
阿新 • • 發佈:2019-01-07
利用
error_page
指令對反向代理返回的404, 302...
等狀態碼,做子請求的二次處理。
client -[1]-> nginx proxy <--[2]--> 站點A(返回404,302)
|[3]
V
站點B (返回200)
- 比如作為CDN的服務時候,站點A返回302,利用子請求提取
location
的url訪問站點B,拿到結果返回給客戶端 - 比如作為下載映象站點,客戶端請求下載檔案,在站點A無法找到返回404,利用子請求請求B站點
測試環境
- macos
- openresty/1.13.6.1
方案一 error_page
下面是個404狀態碼,跳轉到備用站點的模擬例子
server {
listen 8008;
...
# 測試upstream, proxy_pass 錯誤嗎,二次請求,比如說cdn
# 404,302的時候怎麼做子請求跳轉
location = /test_404 {
proxy_pass http://127.0.0.1:9996; # 返回404狀態碼
# uwsgi
# uwsgi_intercept_errors on;
# fastcgi
# fastcgi_intercept_errors on;
proxy_intercept_errors on;
error_page 404 403 = @error_page_404;
}
location @error_page_404 {
content_by_lua_block {
ngx.say('404 => 200')
ngx.exit(200)
}
}
server {
listen 9996;
location /test_404 {
content_by_lua_block {
ngx.exit(404)
}
}
}
注意 proxy_intercept_errors 這個配置要加開啟,它的作用是對於 >=300
error_page
處理流程中。 對應的 uwsgi, fastcgi 方向代理都有類似的指令。
測試
$ curl -i http://127.0.0.1:9996/test_404
HTTP/1.1 404 Not Found
Server: openresty/1.13.6.1
Date: Sun, 22 Apr 2018 02:59:12 GMT
Content-Type: text/html
Content-Length: 175
Connection: keep-alive
$ curl -i 127.0.0.1:8008/test_404
HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Sun, 22 Apr 2018 03:02:45 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
404 => 200
方案二 proxy_next_upstream
主要配置
upstream backend_502_testing {
server 127.0.0.1:9998; # 502, 後端就沒有服務
server 127.0.0.1:9996;
}
server {
listen 8008;
...
# 502為例子,測試 proxy_next_upstream,失敗轉移
location = /test_502 {
proxy_next_upstream error timeout http_502;
proxy_pass http://backend_502_testing;
}
}
server {
listen 9996;
location /test_502 {
content_by_lua_block {
ngx.say('502 => 200')
ngx.exit(200)
}
}
}
測試結果
$ curl -i 127.0.0.1:9998/test_502
curl: (7) Failed to connect to 127.0.0.1 port 9998: Connection refused
$ curl -i 127.0.0.1:9996/test_502
HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Sun, 22 Apr 2018 03:06:17 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
502 => 200
$ curl -i 127.0.0.1:8008/test_502
HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Sun, 22 Apr 2018 03:12:02 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 11
Connection: keep-alive
502 => 200
此時的errlog
2018/04/22 11:12:02 [error] 80096#0: *108 kevent() reported that connect() failed (61: Connection refused) while connecting to upstream, client: 127.0.0.1, server: localhost, request: "GET /test_502 HTTP/1.1", upstream: "http://127.0.0.1:9998/test_502", host: "127.0.0.1:8008"
多次請求 127.0.0.1:8008/test_502
就會發現,upstream不是針對每次請求先訪問 9998埠的服務,在訪問 9996埠的服務,而是當發現 127.0.0.1:9998
服務不可用的時候,有一段時間請求會自動傳送到 127.0.0.1:9996
這個健康的後端上,過一段時間才會繼續嘗試 127.0.0.1:9998
總結
兩種方案比較
- 狀態碼範圍,
error_page
方式(方案一)可以捕獲的狀態碼更多 - 場景區別,針對於每個請求,都要先嚐試
站點1
,如果得到非200狀態碼,在訪問站點2
(這裡也可以增加lua處理), 這種邏輯只能使用方案一。方案二顯然是為負載均衡設計的,針對的是後端的健康狀態,並且也無法做到切換upstream之後的自定義邏輯。
請先理解自己的需求,再做選擇。