多級nginx代理,獲取客戶端真實ip
今天服務裡的微信公眾號支付業務突然不能用了,報錯為網路環境未能通過安全驗證,請稍後再試。檢查後端日誌,沒有任何問題,看來是成功建立支付訂單,但是調起支付時出現了問題。上網查了一下,這個報錯的直接原因是傳入的客戶端ip與調起支付的ip不符。但是印象中我在程式碼中獲取的是X-Forwarded-For,就是請求來源的客戶端IP,就檢視日誌發現傳給微信的ip為172.17.0.1,也就是宿主機ip,這是才恍然大悟,在升級線上環境時我們將所有服務放進了docker,並且在docker裡裝了nginx來分發請求給對應的服務,也就是說我們是兩級nginx代理,我們的服務是沒法拿到最外層客戶端ip的。只好改進nginx將每級代理的ip都記錄起來,而不是直接覆蓋。
改進方法:
對第一級nginx代理
location ~ ^/test { proxy_pass http://127.0.0.1:8888; proxy_set_header Host $host; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; }
第一級nginx代理不需要改動,直接將原始客戶端ip記錄到X-Forwarded-For即可
對於第二級,以及之後可能存在的更多級代理
location ~ ^/test { proxy_pass http://127.0.0.1:12000; proxy_set_header Host $host; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
這樣就將新一級代理的ip接到X-Forwarded-For的尾部,並用逗號分割。也就是說X-Forwarded-For是一個逗號拼接的ip字串,想拿到原始ip只需要按逗號分割,取第一位ip即可。
Golang業務中讀取原始客戶端ip程式碼
real_ip := r.Header.Get("X-Forwarded-For") ip_list := strings.Split(real_ip, ",") if len(ip_list) > 1 { real_ip = ip_list[0] }
就是這麼簡單啦,希望對大家有所幫助~