1. 程式人生 > >負載均衡後獲取客戶端真實ip

負載均衡後獲取客戶端真實ip

String ip3=request.getRemoteAddr(); 如果沒有配負載均衡,則request.getRemoteAddr() 獲取的就是真實客戶端IP,如果配了nginx負載均衡,則request.getRemoteAddr() 獲取的是負載均衡nginx伺服器的ip,而不是真實客戶端IP。

那麼問題來了,經過nginx負載均衡後,如何獲取客戶端真實ip?

location / {
    root   html;
    index  index.html index.htm;
    
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://192.168.81.188:8080;
}
 

程式碼中,Header中使用“X-Forwarded-For”欄位或“X-Real-IP”欄位獲取Client真實 IP。

以一個servlet為例:
 

​​​​​​​    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        //response.getWriter().append("Served at: ").append(request.getContextPath());
        
        PrintWriter writer = response.getWriter();
        //也可以使用小寫的欄位 String ip=request.getHeader("x-forwarded-for");
        String ip=request.getHeader("X-Forwarded-For");
        writer.println("x-forwarded-for_ip:  "+ip);

        //也可以使用小寫的欄位 String ip2=request.getHeader("x-real-ip");
        String ip2=request.getHeader("X-Real-IP");
        writer.println("x-real-ip:  "+ip2);

        String ip3=request.getRemoteAddr();
        writer.println("RemoteAddr:  "+ip3);
        
        
    }

注意:從Header中獲取欄位的時候,是不區分大小寫的。所以 request.getHeader("x-forwarded-for")和request.getHeader("X-Forwarded-For")以及request.getHeader("x-FORWARded-for")效果是一樣的。

 

 

如果通過了多級反向代理的話,X-Forwarded-For的值不止一個,而是一串IP值,此時取第一個IP地址就可以了,第一個IP代表客戶端真實IP,比如:

分析:
從CSN開始,每經過一個代理做一次轉發,x_forwarded_for就會在後面追加一個代理IP。請求到達nginx時,x_forwarded_for已經變成一個以逗號分隔的ip串,並且以轉發順序排序。
nginx的內建變數remote_addr(

)僅能代表nginx的上一層代理的IP,現有的nginx配置將該值賦給X_Real_IP,那麼後端獲取到的X_Real_IP只是nginx上一層代理的IP,而不是客戶端真實的IP。

舉例:如圖,我經過兩層代理,最終到達後端真實業務伺服器:

瀏覽器訪問結果: