1. 程式人生 > >多級nginx代理,獲取客戶端真實ip

多級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]
	}

就是這麼簡單啦,希望對大家有所幫助~