業務層經過獲取請求頭參數便可拿到客戶端IPjava
request.getRemoteAddr();
複製代碼
使用代理後直接讀取請求頭參數會讀取到代理服務器的IP地址,而非真實客戶端IPnginx
解決方法是添加Nginx請求頭參數提早保存客戶端IPbash
nginx.conf
配置加入內容服務器
location / {
...
# IP地址轉發
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
複製代碼
業務層讀取nginx配置的請求頭參數便可測試
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
log.info("【Proxy-Client-IP】 {}", ip);
}
if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
log.info("【WL-Proxy-Client-IP】{}", ip);
}
if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
log.info("【X-Forwarded-For】{}", ip);
}
if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
log.info("【unknown】{}", ip);
}
return ip;
}
複製代碼
若存在多級Nginx代理,則須要在第一級代理時獲取客戶端IP,在後續代理逐層傳遞阿里雲
第一級代理配置同上,第N級代理配置nginx.conf
以下spa
location /{
# IP地址轉發
proxy_set_header X-Real-IP $X-Real-IP;
proxy_set_header X-Real-Port $X-Real-Port;
proxy_set_header X-Forwarded-For $X-Forwarded-For;
}
複製代碼
業務層保持不變便可讀取到傳遞的IP地址代理
在已經存在nginx代理的場景下,加入CDN後源客戶端IP在CDN處被轉發,故第一級nginx代理使用$remote_addr
參數讀取到的是CDN服務的地址,而根據通常約定,CDN轉發會將IP地址存放在X-Forwarded-For
參數下code
修改頂級Nginx配置以支持優先獲取CDN代理地址,也能夠經過修改業務層讀取優先級實現cdn
location / {
...
# IP地址轉發
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
複製代碼
但通過對阿里雲CDN測試,發現X-Forwarded-For
下不只包含真實客戶端IP也包含CDN服務IP,故業務層須要作必定的處理進行區分
如圖,第一個爲真實客戶端IP,第二個爲CDN代理IP
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
log.info("【Proxy-Client-IP】 {}", ip);
}
if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
log.info("【WL-Proxy-Client-IP】{}", ip);
}
if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
if (ip.contains(",")) {
// 經過阿里雲CDN轉發後可能讀取到2個IP地址
String[] cdnMutilIp = ip.split(",");
ip = cdnMutilIp[0];
}
log.info("【X-Forwarded-For】{}", ip);
}
if (ip == null || ip.length() == 0 || " unknown ".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
log.info("【unknown】{}", ip);
}
return ip;
}
}
複製代碼