一、背景介绍
H5 支付要求商户上传用户真实 IP 地址 client_ip,为保证微信端获取的用户 ip 地址与商户端获取的一致,提供了以下获取用户 ip 的指引,希望对大家有所帮助。
二、没有代理的情况
在商户的前端接入层没有做代理的情况下获取 ip 的方式比较简单,直接获取 'REMOTE_ADDR' 即可:
function get_client_ip() { $cip = "unknown"; if ($_SERVER['REMOTE_ADDR']) { $cip = $_SERVER['REMOTE_ADDR']; } elseif (getenv("REMOTE_ADDR")) { $cip = getenv("REMOTE_ADDR"); } return $cip }
三、有代理的情况
在有代理的情况下,因为要代替客户端去访问服务器,所以,当请求包经过反向代理后,在代理服务器这里这个 IP 数据包的 IP 包头做了修改,最终后端 WEB 服务器得到的数据包的头部源 IP 地址是代理服务器的 IP 地址。这样一来,后端服务器的程序就无法获取用户的真实 ip 。
nginx 有代理的情况:
在 nginx 中配置中加入
proxy_set_header Host $host; 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;
Apache 有代理的情况:
vi /usr/local/apache/conf/httpd.conf Include conf/extra/httpd-remoteip.conf vi /usr/local/apache/conf/extra/httpd-remoteip.conf LoadModule remoteip_module modules/mod_remoteip.so RemoteIPHeader X-Forwarded-For RemoteIPInternalProxy 127.0.0.1
代码 示例
string GetClientIp(CgiInput* poInput) { string client_ip = ""; string strClientIPList; GetHttpHeader("X-Forwarded-For", strClientIPList); if (strClientIPList.empty()) { GetHttpHeader("X-Real-IP", strClientIPList); } if (!strClientIPList.empty()) { size_t iPos = strClientIPList.find( "," ); if( iPos != std::string::npos ) { client_ip = strClientIPList.substr( iPos ); } else { client_ip = strClientIPList; } } if (client_ip.empty()) { GetHttpHeader("PROXY_FORWARDED_FOR", strClientIPList); // 做下兼容 if(strClientIPList.empty()) { client_ip = getRemoteAddr(); } else { size_t iPos = strClientIPList.find( "," ); if( iPos != std::string::npos ) { client_ip = strClientIPList.substr( iPos ); } else { client_ip = strClientIPList; } } } if(!MMPayCommFunc::IsIp(client_ip)) client_ip = getRemoteAddr(); return client_ip; }