發生的情境:伺服器端接收用戶端請求的時候,一般需要進行簽名驗證,用戶端IP限定等情況,在進行用戶端IP限定的時候,需要首先擷取該真實的IP。一般分為兩種情況:
方式一、用戶端未經過代理,直接存取伺服器端(nginx,squid,haproxy);
方式二、用戶端通過多級代理,最終到達伺服器端(nginx,squid,haproxy);
用戶端請求資訊都包含在HttpServletRequest中,可以通過方法getRemoteAddr()獲得該用戶端IP。此時如果在使用方式一形式,可以直接獲得該用戶端真實IP。而如果是方式二中通過代理的形式,此時經過多級反向的代理,通過方法getRemoteAddr()得不到用戶端真實IP,可以通過x-forwarded-for獲得轉寄後請求資訊。當用戶端請求被轉寄,IP將會追加在其後並以逗號隔開,例如:10.47.103.13,4.2.2.2,10.96.112.230。
請求中的參數:
request.getHeader("x-forwarded-for") : 10.47.103.13,4.2.2.2,10.96.112.230
request.getHeader("X-Real-IP") : 10.47.103.13
request.getRemoteAddr():10.96.112.230
用戶端訪問經過轉寄,IP將會追加在其後並以逗號隔開。最終準確的用戶端資訊為:
x-forwarded-for 不為空白,則為逗號前第一個IP ; X-Real-IP不為空白,則為該IP ; 否則為getRemoteAddr() ; 程式碼範例:
/** * 擷取使用者真實IP地址,不使用request.getRemoteAddr()的原因是有可能使用者使用了代理軟體方式避免真實IP地址, * 可是,如果通過了多級反向 Proxy的話,X-Forwarded-For的值並不止一個,而是一串IP值 * * @return ip */ private String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); System.out.println("x-forwarded-for ip: " + ip); if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) { // 多次反向 Proxy後會有多個ip值,第一個ip才是真實ip if( ip.indexOf(",")!=-1 ){ ip = ip.split(",")[0]; } } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); System.out.println("Proxy-Client-IP ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); System.out.println("WL-Proxy-Client-IP ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); System.out.println("HTTP_CLIENT_IP ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("X-Real-IP"); System.out.println("X-Real-IP ip: " + ip); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); System.out.println("getRemoteAddr ip: " + ip); } System.out.println("擷取用戶端ip: " + ip); return ip; }此時,正常情況之下可以擷取用戶端真實的IP。需要注意的是對於伺服器端採用負載的形式,需要配置儲存x-forwarded-for。
轉載地址:http://www.cnblogs.com/xiaoxing/p/6565573.html