1. 需求分析
為了在線上環境提供測試分支,規定將某IP轉發到測試程序地址。如果是 ngx 直接對外,采用 real_ip 就能夠做限制,但是最前端確實一個7層是負載均衡就需要研究一番了。
2. 實踐
業務部署在某雲上,前端上掛着一個7層的負載均衡,通過查看官方可以通過 X-Forwarded-For 來獲取客戶端真實IP,這樣就很簡單了。
通過測試模擬這樣的環境驗證下:
192.168.118.14 - ngx :該ngx 只是充當負載均衡,開啟 X-Forwarded-For
192.168.118.15 - ngx:該ngx 為 web服務器,真正的用戶端IP判斷在這里實現
192.168.118.16 - httpd:充當 測試程序
配置如下:
192.168.118.14(模擬負載均衡):
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 轉發客戶端真實IP
location / {
proxy_pass http://192.168.118.15/; # 僅僅用作轉發
access_log logs/14_access.log main;
error_log logs/14_error.log;
#root html;
#index index.html index.htm;
}
192.168.118.15(nginx - 用戶端IP判斷在此實現)
upstream back1 {
server 192.168.118.16:8080;
}
server {
listen 80;
server_name localhost;
location / {
if ($http_x_forwarded_for ~* "192.168.118.2") {
rewrite ^/(.*)$ http://192.168.118.15/back1/$1 break;
}
root html;
index index.html;
access_log logs/15_access.log main;
error_log logs/15_error.log;
}
location /back1 {
proxy_pass http://back1/;
}
因為負載均衡可以轉發用戶真實IP,所以在 nginx 中,直接判斷 http_x_forwarded_for 就能做路由。
192.168.118.16 開啟 8080 端口
# curl http://192.168.118.16:8080/a.html <h1>192.168.118.16: a.html</h1>
直接訪問 192.168.118.15
# curl http://192.168.118.15/a.html <h1>192.168.118.15: a.html</h1>
定義的規則:當客戶端 192.168.118.2 訪問 192.168.118.14時,則轉發到 192.168.118.16:8080,剩下其他客戶端IP則直接訪問 192.168.118.15
3. 驗證
通過 192.168.118.2 客戶端訪問:
http://192.168.118.14/a.html 地址在瀏覽器已經經過 302 跳轉到新的連接地址了。

其他客戶端IP訪問:

4. 后續
通過 rewrite 這種方式實現了條件判斷的跳轉,但是這個跳轉是 HTTP 302 並不支持 head 等信息的轉發,所以在提交 post 請求時,會出現錯誤。
在生產環境中,有這樣一個實例:

需求:當IP: 192.168.118.2 訪問 http://192.168.118.15/bbs/ 時,跳轉到 http://192.168.118.16:8080/ uri中不能帶有 /bbs
實現:

注意:在條件判斷的反向代理中,proxy_pass http://192.168.118.16:8080 后面不得帶 '/' 或者其他路徑,否則 nginx -t 檢測會報錯。報錯信息如下:
[root@localhost conf]# nginx -t nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /usr/local/nginx/conf/nginx.conf:50 nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed
