获取客户端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
这样的确能够获取到ip,但是企业应用的时候会出问题,这里先不说,假定可以(见3)。
2.问题2-测试
问题来了,获取到局域网的ip了,调用17mon的api得到的结果是 “局域网”
所以,局域网是测试不了这个的(至少我没什么好的办法),于是搬到了公司的stage(外网)环境测试
3.问题3-获取到的ip为127.0.0.1
为什么?因为公司有ngnix反向代理服务器,客户端的ip地址被他吞掉了,
怎么办?让ngnix吐出来:
这里返回的string,很有可能是有多个ip,用 "," 分隔开了。这多个ip就是一层层的多个代理,我们只要获取到第一个有效的即可。
五。我在这里碰到的问题:
公司有写好的api,所以我直接就拿过来用了,x-forwarded-for什么的我也没管,他都有。
但是我在调用的时候无法得到 x-forwarded-for 的header(重复加日志,部署,好累的说)。
然后就想,客户端本来应该访问服务器的,现在中间通过了代理,平常我们访问服务器也是没有 x-forwarded-for这个参数的,那么这个参数,一定是代理那边为了留下客户端的踪迹加进去的;于是网上搜 ngnix x-forwarded-for,果然是ngnix中未配置该项属性,添上。ok。
六。上代码:
网上获取ip的都是这一套,拿了公司的代码(跟网上的大致一样),应该不会被打吧。。。
最近在做的一个模块中,有一个后台统计功能要求按照用户的省份来统计。
所以在用户操作的时候,后台就应该得到其地理位置信息,并存放在数据库中。
二。分析
作为一个移动应用,要想定位用户
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; }
相关文章推荐
- 房产界已上市和IPO路上的难兄难弟:房天下与房多多
- 雷军是谁,他为什么而奋斗?小米上市和雷军的英雄主义
- IP网络路由技术
- 如何利用“IP地址欺骗”
- 新手看招:避免网络 IP 地址被非法修改
- 网络管理之IP地址篇
- ip地址基础知识
- 脚本之家因服务器资源紧张 换了ip并升级了带宽
- IP地址组成与类型
- 计算机名DNS网关IP(大家可以用来学习)
- Windows2003下批量添加和导出所有ip BAT脚本
- 一个能对访问者进行编号、记录访问次数、IP、时间的统计制作实例
- 用vbscript脚本实现返回 IP 配置数据的代码
- 用vbs针对一个 IP 地址范围运行脚本
- asp实现检查ip地址是否为内网或者私有ip地址的代码分享
- 根据IP跳转到用户所在城市的实现步骤
- vbs版IP地理位置查询小偷
- bat脚本显示本机IP地址的两种方法(内网ip)
- PHP判断IP并转跳到相应城市分站的方法