Nginx暴露出請(qǐng)求的真實(shí)IP的問(wèn)題
前言
在工作中,經(jīng)常會(huì)用用戶(hù)實(shí)際請(qǐng)求的 IP 地址,當(dāng)需要記錄到日志信息時(shí)或者在請(qǐng)求其他的第三方接口時(shí)需要用到實(shí)際的用戶(hù) IP 地址傳入,在本節(jié)中會(huì)提供服務(wù)端在實(shí)際獲取 IP 地址的源碼以及通過(guò) Nginx 代理后 IP 地址隱藏的問(wèn)題
用途/場(chǎng)景
獲取經(jīng)緯度
無(wú)論是小程序還是 App 端,當(dāng)用戶(hù)未開(kāi)啟地理位置授權(quán)時(shí),在前端頁(yè)面是無(wú)法拿到當(dāng)前用戶(hù)所在的經(jīng)緯度信息的,這時(shí)候還有另外一種途徑來(lái)獲取經(jīng)緯度,那就是通過(guò) IP 地址來(lái)解析用戶(hù)真實(shí)請(qǐng)求時(shí)所在的經(jīng)緯度
在一般情況下,都是由前端來(lái)拿到這塊請(qǐng)求的 IP,可能由于某些 API 或版本的限制,導(dǎo)致前端在所獲取的 IP 地址不準(zhǔn)確,此時(shí),不得不讓后端的大佬 CASE 出手了
支付接口

微信 > 小程序支付文檔中,終端IP:spbill_create_ip 參數(shù)是必填項(xiàng),雖然在微信那一側(cè)不會(huì)去校驗(yàn)這塊的 IP 地址是否準(zhǔn)確,但真實(shí)的 IP 地址有利用我們?nèi)ヅ挪榫€上問(wèn)題,比如 IP 地址都是 127.0.0.1 這樣的,你永遠(yuǎn)都分辨不出到底請(qǐng)求是從那一塊服務(wù)進(jìn)來(lái)的
白名單配置
當(dāng)請(qǐng)求第三方接口 API 時(shí),若我們所請(qǐng)求的 IP 地址未配置進(jìn)白名單時(shí),我們是無(wú)法從第三方獲取到我們想要得到的信息的,這時(shí)候有了前置或后置日志打印我們請(qǐng)求時(shí)的 IP,能夠更快的幫助我們解決問(wèn)題
比較友善的第三方 API,在我們請(qǐng)求接口出現(xiàn)白名單的問(wèn)題,會(huì)將我們的 IP 進(jìn)行返回提示 “該 IP:Xxx,未配置白名單,請(qǐng)聯(lián)系管理員!”,這時(shí)直接拿到返回的錯(cuò)誤信息內(nèi)容進(jìn)行配置即可,無(wú)須任何的日志輸入
但是有的第三方 API 就比較雞肋,只是返回一段 "請(qǐng)求 IP 未配置白名單,請(qǐng)聯(lián)系管理員!”,這時(shí)候如果不+日志打印,那中間去找部署服務(wù)的 IP 花費(fèi)的時(shí)間就比這日志打印的時(shí)間多了個(gè)去
實(shí)現(xiàn)源碼
請(qǐng)求工具類(lèi)
/**
* @author vnjohn
* @since 2023/10/30
*/
public class IPv4Util {
private static final String HEADER_FORWARDED_FOR = "x-forwarded-for";
private static final String HEADER_PROXY_CLIENT_IP = "Proxy-Client-IP";
private static final String HEADER_WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
private static final String HEADER_HTTP_CLIENT_IP = "http_client_ip";
private static final String HEADER_HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR";
private static final String UNKNOWN = "unknown";
private static final String CHAR_COLON = ":";
private static final String CHAR_COMMA = ",";
public static String getClientIp(HttpServletRequest request) {
String ip = request.getHeader(HEADER_FORWARDED_FOR);
boolean ipIsEmpty = ip == null || ip.length() == 0;
if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader(HEADER_PROXY_CLIENT_IP);
}
if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader(HEADER_WL_PROXY_CLIENT_IP);
}
if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader(HEADER_HTTP_CLIENT_IP);
}
if (ipIsEmpty || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader(HEADER_HTTP_X_FORWARDED_FOR);
}
// 如果是多級(jí)代理,那么取第一個(gè)ip為客戶(hù)ip
if (ip != null && ip.contains(CHAR_COMMA)) {
ip = ip.substring(ip.lastIndexOf(CHAR_COMMA) + 1, ip.length()).trim();
}
//判斷IP是否存在帶有端口號(hào)的情況、應(yīng)該要去掉端口號(hào)
if (ip != null && ip.contains(CHAR_COLON)) {
ip = ip.substring(0, ip.indexOf(CHAR_COLON));
}
return ip;
}
/**
* 獲取請(qǐng)求的ip
*/
public static String getRequestIp() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 從獲取 RequestAttributes 中獲取 HttpServletRequest 信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
public static void main(String[] args) {
System.out.println(getRequestIp());
}
}
在其他地方,需要獲取 IP 時(shí),只需要按如下傳入?yún)?shù):
HttpServletRequest request
如下調(diào)用即可:
IPv4Util.getClientIp(request);
Nginx 代理配置
在 server 標(biāo)簽?zāi)K中指定的請(qǐng)求前綴配置一個(gè) location 或直接在 server 標(biāo)簽內(nèi)進(jìn)行配置,如下:
location /app {
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://localhost:8084;
}
只有當(dāng)設(shè)置了 proxy_set_header X-Real-IP 代理參數(shù)以后,獲取服務(wù)請(qǐng)求的 IP 才是準(zhǔn)確的
小結(jié)
注意:只有在 Nginx 代理配置以下內(nèi)容以后,通過(guò)請(qǐng)求工具類(lèi)才能獲取到真實(shí)的 IP 地址!??!
總結(jié)
該篇博文主要介紹的是如何在服務(wù)端中獲取用戶(hù)請(qǐng)求的真實(shí) IP 地址,通過(guò)幾種用途/場(chǎng)景介紹其所在的必要性:獲取經(jīng)緯度、支付接口、白名單配置,當(dāng)然,為了讓你能夠快速的運(yùn)用起來(lái),提供了請(qǐng)求工具類(lèi)的源碼以及告知你如何在 Nginx 進(jìn)行代理配置,希望這篇短文能夠幫助到您,解決您實(shí)際工作中的一些問(wèn)題
到此這篇關(guān)于Nginx暴露出請(qǐng)求的真實(shí)IP的問(wèn)題解決的文章就介紹到這了,更多相關(guān)Nginx暴露請(qǐng)求的真實(shí)IP內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nginx搭建文件服務(wù)器的詳細(xì)過(guò)程
這篇文章主要介紹了nginx搭建文件服務(wù)器,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
shell腳本定時(shí)統(tǒng)計(jì)Nginx下access.log的PV并發(fā)送給API保存到數(shù)據(jù)庫(kù)
這篇文章主要介紹了shell腳本定時(shí)統(tǒng)計(jì)Nginx下access.log的PV并發(fā)送給API保存到數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方法 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09
nginx實(shí)現(xiàn)一個(gè)域名配置多個(gè)laravel項(xiàng)目的方法示例
這篇文章主要介紹了nginx實(shí)現(xiàn)一個(gè)域名配置多個(gè)laravel項(xiàng)目的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
nginx 配置代理服務(wù)地址最后多加反斜杠和不加反斜杠的區(qū)別小結(jié)
在使用Nginx配置代理服務(wù)時(shí),地址最后是否添加反斜杠(/)會(huì)對(duì)代理的URL處理產(chǎn)生影響,下面就來(lái)具體介紹一下,感興趣的可以了解一下2024-08-08
nginx proxy_redirect的作用及說(shuō)明
這篇文章主要介紹了nginx proxy_redirect的作用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06

