今天幫兄弟項目搞了一個獲取客戶端真實IP的問題,網上這種問題很多,但是對於我們的場景都不太合用,現把我的解決方案share給大家,如有問題,請及時指出。
場景:
在請求到達后端服務之前,會經過層層代理的轉發。
一般的解決方案:
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
后端服務獲取客戶端真實IP的方法:
request.getAttribute("X-real-ip")
現象:
后端服務獲取到的IP並不是客戶端真實IP,而是某一級代理的IP。
分析:
從CDN開始,每經過一個代理做一次轉發,x_forwarded_for就會在后面追加一個代理IP。請求到達nginx時,x_forwarded_for已經變成一個以逗號分隔的ip串,並且以轉發順序排序。
nginx的內置變量remote_addr僅能代表nginx的上一層代理的IP,現有的nginx配置將該值賦給X_Real_Ip,那么后端獲取到的X_Real_Ip也是nginx上一層代理的IP,而不是客戶端真實IP。
解決方案:
x_forwarded_for中的IP串,第一個IP即可代表客戶端真實IP,因此可在nginx上對x_forwarded_for做一個正則匹配,獲取第一個逗號之前的IP賦值給X-real-ip,從而達到不需要修改應用即可獲取客戶端真實IP的目的。
示例配置如下:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
set $Real $http_x_forwarded_for;
if ( $Real ~ (\d+)\.(\d+)\.(\d+)\.(\d+),(.*) ){
set $Real $1.$2.$3.$4;
}
proxy_set_header X-Real-Ip $Real;