問題現(xiàn)象
- 我們的平臺使用Spring Cloud微服務(wù)架構(gòu),使用Spring Boot構(gòu)建Java服務(wù),使用google的jib插件打成docker鏡像包
- 我們使用docker虛擬化部署,使用docker-compose統(tǒng)一管理所有服務(wù),包括Java服務(wù)和nginx等組件
- 我們前后端分離,前端通過nginx訪問我們的網(wǎng)關(guān)(Spring Cloud Gateway),再轉(zhuǎn)發(fā)到對應(yīng)的Java服務(wù)
- 我們需要記錄一些基礎(chǔ)業(yè)務(wù)數(shù)據(jù)變動日志,于是在過濾器里攔截對應(yīng)請求記錄日志
- 在記錄操作的來源ip時,記錄了一個
172.18.0.x
的地址,這個明顯不是實(shí)際客戶端來源的ip
排查解決
- 我們使用
getRemoteAddres(request)
獲取的ip地址,按理說是能獲取到客戶端的真實(shí)ip地址的 - 地址不對,想著從request的header里直接獲取,參考網(wǎng)上的方法,查看哪個header參數(shù)里有ip地址
log.info("X-Real-IP={}", request.getHeader("X-Real-IP"));
log.info("X-Original-Forwarded-For={}", request.getHeader("X-Original-Forwarded-For"));
log.info("X-Forwarded-For={}", request.getHeader("X-Forwarded-For"));
log.info("x-forwarded-for={}", request.getHeader("x-forwarded-for"));
log.info("Proxy-Client-IP={}", request.getHeader("Proxy-Client-IP"));
log.info("WL-Proxy-Client-IP={}", request.getHeader("WL-Proxy-Client-IP"));
log.info("HTTP_CLIENT_IP={}", request.getHeader("HTTP_CLIENT_IP"));
log.info("HTTP_X_FORWARDED_FOR={}", request.getHeader("HTTP_X_FORWARDED_FOR"));
-
結(jié)果發(fā)現(xiàn),只有
X-Forwarded-For
能獲取到地址,還是那個錯誤的172.18.0.x
的地址 -
地址不對,應(yīng)該是哪里出了問題,可能是docker網(wǎng)絡(luò)、nginx代理或者gateway網(wǎng)關(guān)
-
進(jìn)一步排查,這個地址之前看到過,
172.1x.0.x
,是docker網(wǎng)絡(luò)生成的ip地址 -
使用docker命令
docker network ls
,查看了docker網(wǎng)絡(luò)后,發(fā)現(xiàn)我們確實(shí)用的是這個 -
繼續(xù)查看各個docker服務(wù)的ip,確定下這個ip是哪個服務(wù)的,具體來說,是nginx的、gateway的,還是具體的這個Java應(yīng)用的
-
使用
docker exec -it 服務(wù)名 /bin/bash
進(jìn)入docker容器內(nèi)部,使用cat /etc/hosts
查看網(wǎng)絡(luò)配置 -
對比發(fā)現(xiàn)這個ip是nginx服務(wù)的,說明獲取客戶端遠(yuǎn)程地址時,獲取到了nginx的ip
-
nginx是決定能獲取到正確的客戶端請求ip地址的,因?yàn)樗膌og日志輸出里,是有來源ip的
修改nginx配置
- 查看了nginx的配置文件
default.conf
,發(fā)現(xiàn)里面沒有其他配置,已有的X-Forwarded-For
配置為proxy_set_header X-Forwarded-For $proxy_protocol_addr;
,這里直接把nginx代理服務(wù)自己的地址賦給了X-Forwarded-For
,所以我們獲取到的是nginx的地址 - 我們現(xiàn)在需要做的,主要是在主配置文件,添加一行
proxy_set_header X-Real-IP $remote_addr;
,將客戶端的真實(shí)ip地址,賦給X-Real-IP
- 執(zhí)行命令
docker restart nginx
,重啟nginx使其生效
Java代碼
- Java代碼修改也很簡單,對應(yīng)nginx的配置,獲取
X-Real-IP
即可
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
- 成功獲取,結(jié)束
nginx配置proxy_set_header介紹
在Nginx配置中,proxy_set_header
指令是用于定義向代理服務(wù)器傳遞的請求頭字段。該指令專門用于location
塊中,并且通常配合 proxy_pass
指令一起工作,proxy_pass
指令定義了代理服務(wù)器的協(xié)議和地址。
基本上,當(dāng)Nginx作為反向代理服務(wù)器時,客戶端的請求首先到達(dá)Nginx,然后Nginx將這些請求轉(zhuǎn)發(fā)到后端的上游服務(wù)器。在轉(zhuǎn)發(fā)請求時,Nginx可以設(shè)置或修改請求頭。proxy_set_header
指令正是用來進(jìn)行這樣的設(shè)置或修改。
下面是幾個proxy_set_header
常見用例:
-
傳遞主機(jī)名 - 將客戶端請求的原主機(jī)頭信息傳遞到上游服務(wù)器。
proxy_set_header Host $host;
-
傳遞真實(shí)IP地址 - 將客戶端的真實(shí)IP地址傳遞給后端應(yīng)用,這在后端應(yīng)用需要記錄真實(shí)的客戶端地址時非常有用。
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
傳遞HTTPS相關(guān)信息 - 當(dāng)Nginx用作SSL終結(jié)時,它可以告訴后端應(yīng)用請求是通過HTTPS或HTTP進(jìn)行的。
proxy_set_header X-Forwarded-Proto $scheme;
-
用戶的Worker處理狀態(tài): 有時,應(yīng)用程序可能需要知道客戶端連接的具體狀態(tài)。
proxy_set_header Connection $connection_upgrade;
標(biāo)準(zhǔn)的 proxy_set_header
指令使用方法如下:
proxy_set_header Header-Name Header-Value;
-
Header-Name
是你希望設(shè)置的HTTP請求頭名稱。 -
Header-Value
是對應(yīng)的值,它可能是一個固定的字符串,也可以是Nginx提供的變量,如$remote_addr
、$http_user_agent
、$http_cookie
等。
注意,默認(rèn)情況下,Nginx會使用某些標(biāo)準(zhǔn)請求頭,如Host
、Connection
等,如果你沒有明確使用proxy_set_header
設(shè)置它們,Nginx會傳遞它的默認(rèn)值。文章來源:http://www.zghlxwxcb.cn/news/detail-802169.html
在調(diào)整Nginx作為反向代理服務(wù)器時,正確配置proxy_set_header
指令能確保后端服務(wù)器可以接收到所需的所有重要信息,提供正確和安全的服務(wù)。文章來源地址http://www.zghlxwxcb.cn/news/detail-802169.html
到了這里,關(guān)于docker:Java通過nginx獲取客戶端的真實(shí)ip地址的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!