您的位置:首页 > 其它

获取客户端IP地址(多层代理)

2015-11-23 22:09 211 查看
一。需求

最近在做的一个模块中,有一个后台统计功能要求按照用户的省份来统计。

所以在用户操作的时候,后台就应该得到其地理位置信息,并存放在数据库中。

二。分析

作为一个移动应用,要想定位用户

1.可以通过客户端系统(android,ios)获取,(以前android做过使用百度lbs定位的)

2.可以通过h5页面,gps定位(前台调用一些接口我也不太懂,好像能这样吧,反正这不是重点)

3.可以通过后台ip地址,然后通过ip库查找定位

由于公司里面使用的是h5页面,所以定位就交给了h5以及后台。

又由于前台嫌麻烦,所以定位就采用上述的第三种方法来做。

虽然ip地址一直在更新,用这种方法做不一定能够保持准确,但是确实最简单的。

三。动手开搞

刚好之前公司也有项目使用过定位

之前使用的是经纬度+ip,先让客户端传经纬度,如果没传过来,那么后台通过ip来判断。

到了我这里,直接就通过ip判断。

拿到以前用的代码,看了一通,原来用的是17mon 的免费api,那么这个方面就不多说了,就是根据文档调api。

现在的问题是,获取IP地址。

四。获取ip

1.问题1-调用api

request.getRemoteAddr();


这样的确能够获取到ip,但是企业应用的时候会出问题,这里先不说,假定可以(见3)。

2.问题2-测试

问题来了,获取到局域网的ip了,调用17mon的api得到的结果是 “局域网”

所以,局域网是测试不了这个的(至少我没什么好的办法),于是搬到了公司的stage(外网)环境测试

3.问题3-获取到的ip为127.0.0.1

为什么?因为公司有ngnix反向代理服务器,客户端的ip地址被他吞掉了,

怎么办?让ngnix吐出来:

request.getHeader("x-forwarded-for")


这里返回的string,很有可能是有多个ip,用 "," 分隔开了。这多个ip就是一层层的多个代理,我们只要获取到第一个有效的即可。

五。我在这里碰到的问题:

公司有写好的api,所以我直接就拿过来用了,x-forwarded-for什么的我也没管,他都有。

但是我在调用的时候无法得到 x-forwarded-for 的header(重复加日志,部署,好累的说)。

然后就想,客户端本来应该访问服务器的,现在中间通过了代理,平常我们访问服务器也是没有 x-forwarded-for这个参数的,那么这个参数,一定是代理那边为了留下客户端的踪迹加进去的;于是网上搜 ngnix x-forwarded-for,果然是ngnix中未配置该项属性,添上。ok。

六。上代码:

网上获取ip的都是这一套,拿了公司的代码(跟网上的大致一样),应该不会被打吧。。。

/**
* 获取客户端IP地址
*
* @param request request 请求
* @return 有效地远程地址
*/
public static String getClientIp(HttpServletRequest request) {

String remoteAddr = request.getHeader("x-forwarded-for");
logger.info("remoteAddr:" + remoteAddr);
// 如果通过多级反向代理,X-Forwarded-For的值不止一个,而是一串用逗号分隔的IP值,此时取X-Forwarded-For中第一个非unknown的有效IP字符串
if (isEffective(remoteAddr) && (remoteAddr.indexOf(",") > -1)) {
String[] array = remoteAddr.split(",");
for (String element : array) {
if (isEffective(element)) {
remoteAddr = element;
break;
}
}
}
if (!isEffective(remoteAddr)) {
remoteAddr = request.getHeader("x-real-ip");
logger.info("request.getHeader(\"X-Real-IP\"):" + remoteAddr);
}
if (!isEffective(remoteAddr)) {
remoteAddr = request.getRemoteAddr();
logger.info("request.getRemoteAddr():" + remoteAddr);
}
return remoteAddr;
}

/**
* 远程地址是否有效.
*
* @param remoteAddr 远程地址
* @return true代表远程地址有效,false代表远程地址无效
*/
private static boolean isEffective(final String remoteAddr) {
boolean isEffective = false;
if ((null != remoteAddr) && (!"".equals(remoteAddr.trim())) && (!"unknown".equalsIgnoreCase(remoteAddr.trim()))) {
isEffective = true;
}
return isEffective;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ip ngnix