JAVA服务器端获取客户端远程地址,根据IP获取远程地址,各IP地址查询接口比较
标签: IP地址查询 HTTPS 多线程 SocketTimeoutExcepti 远程地址查询 更多
一、根据远程请求,获取远程IP
-
/**
-
* Copyright (c) 2016,sunnybs.
-
* All Rights Reserved.
-
*
-
* Project Name:sunego-commerce-common
-
* Package Name:com.sunego.commerce.common.http
-
* File Name:IPUtils.java
-
* Date:2016年4月28日 上午11:23:53
-
*
-
*/
-
package com.sunego.commerce.common.http;
-
import javax.servlet.http.HttpServletRequest;
-
/**
-
* ClassName: IPUtils <br/>
-
* Description: IP查询工具 <br/>
-
* Date: 2016年4月28日 上午11:23:53 <br/>
-
* <br/>
-
*
-
* @author Administrator(邮箱)
-
*
-
* 修改记录
-
* @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>
-
*
-
*/
-
public class IPUtils {
-
public static Address address;
-
/**
-
*
-
* getRemoteIP:获取远程请求客户端的外网IP <br/>
-
*
-
* @param request
-
* 请求实体对象
-
* @return ip 外网ip<br/>
-
*/
-
public static String getRemoteIP(HttpServletRequest request) {
-
String ip = request.getHeader("x-forwarded-for");
-
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-
ip = request.getHeader("Proxy-Client-IP");
-
}
-
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-
ip = request.getHeader("WL-Proxy-Client-IP");
-
}
-
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-
ip = request.getRemoteAddr();
-
}
-
return ip;
-
}
-
/**
-
*
-
* getAddresses:根据外网ip,判断该ip所在的地理位置 <br/>
-
*
-
* @param ip
-
* 外网ip
-
* @return 该ip所在的地理位置 <br/>
-
*/
-
public static String getAddresses(String ip) {
-
return Address.getSingleInstance().getAddresses(ip);
-
}
-
}
二、根据远程IP,获取远程物理地址
-
/**
-
* Copyright (c) 2016,sunnybs.
-
* All Rights Reserved.
-
*
-
* Project Name:sunego-commerce-common
-
* Package Name:com.sunego.commerce.common.http
-
* File Name:Address.java
-
* Date:2016年4月28日 上午11:51:05
-
*
-
*/
-
package com.sunego.commerce.common.http;
-
import java.util.HashMap;
-
import java.util.Map;
-
import java.util.concurrent.ExecutorService;
-
import java.util.concurrent.Executors;
-
import org.apache.commons.lang3.StringUtils;
-
import com.sunego.commerce.common.json.JsonUtils;
-
import com.sunego.commerce.common.log.LogUtils;
-
/**
-
* ClassName: Address <br/>
-
* Description: TODO <br/>
-
* Date: 2016年4月28日 上午11:51:05 <br/>
-
* <br/>
-
*
-
* @author Administrator(邮箱)
-
*
-
* 修改记录
-
* @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>
-
*
-
*/
-
public class Address {
-
/** 多线程公共变量,key=ip,value=address */
-
static final Map<String, String> ipAddressMap = new HashMap<String, String>();
-
/** 线程池线程数 */
-
static final Integer threadSize = 3;
-
/** 太平洋ip地址查询接口 */
-
static final String urlPcOnline = "http://whois.pconline.com.cn/ipJson.jsp?ip={ip}&timeStamp={timeStamp}";
-
/** 淘宝ip地址查询接口 */
-
static final String urlTaobao = "http://ip.taobao.com/service/getIpInfo.php?ip={ip}&timeStamp={timeStamp}";
-
/** 百度ip地址查询接口 */
-
static final String urlBaidu = "http://opendata.baidu.com/api.php?resource_id=6006&format=json&query={ip}&timeStamp={timeStamp}";
-
/**
-
* 私有化构造方法
-
*/
-
private Address() {
-
};
-
private static Address address;
-
/**
-
* 单例模式
-
*/
-
public static Address getSingleInstance() {
-
if (null == address) {
-
// 懒加载
-
synchronized (Address.class) {
-
if (null == address) {
-
address = new Address();
-
}
-
}
-
}
-
return address;
-
}
-
/**
-
* 根据远程ip,查询对应的物理地址<br/>
-
* 只返回所查询到的地址的最后一级,例如address="北京市海淀区西二旗",则返回"西二旗"<br/>
-
* 使用太平洋、淘宝、百度三个ip地址查询接口,多进程异步查询<br/>
-
*/
-
public String getAddresses(String ip) {
-
// 清除上次查询结果
-
ipAddressMap.remove(ip);
-
// 创建一个可以执行三个线程的线程池
-
ExecutorService pool = Executors.newFixedThreadPool(threadSize);
-
// 记录起始查询时间,超时未查到就返回空
-
Long begin = System.currentTimeMillis();
-
// 设置时间戳,防止ip查询接口缓存数据
-
String timeStamp = String.valueOf(begin);
-
// 太平洋ip接口查询
-
pool.execute(new AddressPcOnline(ip, timeStamp));
-
// 淘宝ip接口查询
-
pool.execute(new AddressTaobao(ip, timeStamp));
-
// 百度ip接口查询
-
pool.execute(new AddressBaidu(ip, timeStamp));
-
// 开始判断是否查询到结果
-
while (null == ipAddressMap.get(ip) && System.currentTimeMillis() - begin < 3000) {
-
// 还未获得地址,且未超时(3秒),就等待(50毫秒)
-
try {
-
Thread.sleep(50);
-
} catch (InterruptedException e) {
-
// 返回空
-
return null;
-
}
-
}
-
// 立即关闭所有进程
-
pool.shutdownNow();
-
// 返回查询到的结果
-
return ipAddressMap.get(ip);
-
}
-
public class AddressPcOnline implements Runnable {
-
private String ip;
-
private String timeStamp;
-
String address;
-
AddressPcOnline(String ip, String timeStamp) {
-
this.ip = ip;
-
this.timeStamp = timeStamp;
-
}
-
@Override
-
public void run() {
-
try {
-
String result = NHttpPool.getString(urlPcOnline.replace("{ip}", ip).replace("{timeStamp}", timeStamp),
-
NHttpPool.CHARSET_GBK);
-
result = StringUtils.trim(result);
-
result = result.substring(34, result.length() - 3);
-
Map<?, ?> jsonResult = JsonUtils.toObject(result, Map.class);
-
if (StringUtils.isNotBlank(ipAddressMap.get(ip))) {
-
return;
-
}
-
LogUtils.LOG_BIZ_INFO.info("urlPcOnline | ip=" + ip + " | result=" + result);
-
address = (String) jsonResult.get("region");
-
if (StringUtils.isNotEmpty(address)) {
-
ipAddressMap.put(ip, address);
-
return;
-
}
-
address = (String) jsonResult.get("city");
-
if (StringUtils.isNotEmpty(address)) {
-
ipAddressMap.put(ip, address);
-
return;
-
}
-
address = (String) jsonResult.get("pro");
-
ipAddressMap.put(ip, address);
-
} catch (Exception e) {
-
}
-
}
-
}
-
public class AddressTaobao implements Runnable {
-
private String ip;
-
private String timeStamp;
-
String address;
-
AddressTaobao(String ip, String timeStamp) {
-
this.ip = ip;
-
this.timeStamp = timeStamp;
-
}
-
@Override
-
public void run() {
-
try {
-
String result = NHttpPool.getString(urlTaobao.replace("{ip}", ip).replace("{timeStamp}", timeStamp),
-
NHttpPool.CHARSET_GBK);
-
result = result.substring(17, result.length() - 1);
-
Map<?, ?> jsonResult = JsonUtils.toObject(result, Map.class);
-
if (StringUtils.isNotBlank(ipAddressMap.get(ip))) {
-
return;
-
}
-
LogUtils.LOG_BIZ_INFO.info("urlTaobao | ip=" + ip + " | result=" + result);
-
address = (String) jsonResult.get("county");
-
if (StringUtils.isNotEmpty(address)) {
-
ipAddressMap.put(ip, address);
-
return;
-
}
-
address = (String) jsonResult.get("city");
-
if (StringUtils.isNotEmpty(address)) {
-
ipAddressMap.put(ip, address);
-
return;
-
}
-
address = (String) jsonResult.get("region");
-
ipAddressMap.put(ip, address);
-
} catch (Exception e) {
-
}
-
}
-
}
-
public class AddressBaidu implements Runnable {
-
private String ip;
-
private String timeStamp;
-
String address;
-
AddressBaidu(String ip, String timeStamp) {
-
this.ip = ip;
-
this.timeStamp = timeStamp;
-
}
-
@Override
-
public void run() {
-
try {
-
String result = NHttpPool.getString(urlBaidu.replace("{ip}", ip).replace("{timeStamp}", timeStamp),
-
NHttpPool.CHARSET_GBK);
-
result = result.substring(49, result.length() - 2);
-
Map<?, ?> jsonResult = JsonUtils.toObject(result, Map.class);
-
if (StringUtils.isNotBlank(ipAddressMap.get(ip))) {
-
return;
-
}
-
LogUtils.LOG_BIZ_INFO.info("urlBaidu | ip=" + ip + " | result=" + result);
-
address = (String) jsonResult.get("location");
-
if (address.indexOf(" ") > 0) {
-
address = address.substring(0, address.indexOf(" "));
-
}
-
if (address.indexOf("省") + 1 == address.length()) {
-
ipAddressMap.put(ip, address);
-
return;
-
}
-
if (address.indexOf("市") + 1 == address.length()) {
-
address = address.substring(address.indexOf("省") + 1);
-
ipAddressMap.put(ip, address);
-
return;
-
}
-
address = address.substring(address.indexOf("市") + 1, address.length());
-
ipAddressMap.put(ip, address);
-
} catch (Exception e) {
-
}
-
}
-
}
-
}
三、测试用例
-
/**
-
* Copyright (c) 2016,sunnybs.
-
* All Rights Reserved.
-
*
-
* Project Name:sunego-commerce-common
-
* Package Name:com.sunego.commerce.common.price
-
* File Name:PriceUtilsTest.java
-
* Date:2016年2月20日 下午2:55:35
-
*
-
*/
-
package com.sunego.commerce.common.price;
-
import java.util.ArrayList;
-
import java.util.List;
-
import org.junit.Test;
-
import com.sunego.commerce.common.http.IPUtils;
-
/**
-
* ClassName: PriceUtilsTest <br/>
-
* Description: TODO <br/>
-
* Date: 2016年2月20日 下午2:55:35 <br/>
-
* <br/>
-
*
-
* @author WSP(邮箱)
-
*
-
* 修改记录
-
* @version 产品版本信息 yyyy-mm-dd 姓名(邮箱) 修改信息<br/>
-
*
-
*/
-
public class IPUtilsTest {
-
@Test
-
public void testIPUtils() {
-
/**
-
* 以下接口不可用 <br>
-
* "http://www.hujuntao.com/api/ip/ip.php";<br>
-
* "http://fw.qq.com/ipaddress";<br>
-
* "http://pv.sohu.com/cityjson";// 仅支持js,不接受ip参数<br>
-
* "http://j.maxmind.com/app/geoip.js";<br>
-
* "http://www.youdao.com/smartresult-xml/search.s";<br>
-
* "http://ip.ws.126.net/ipquery";// 仅支持js<br>
-
* "http://app.hao123.com/ipquery/getcity.php?rtype=2";<br>
-
* "http://w.1616.net/chaxun/iptolocal.php?ip=";// 太慢<br>
-
*/
-
List<String> ipList = new ArrayList<String>();
-
ipList.add("219.137.144.0");// 广东省广州市海珠区
-
ipList.add("1.85.35.131");// 陕西省西安市 电信
-
ipList.add("59.108.111.0");// 北京市北京市 方正宽带
-
ipList.add("59.104.167.0");// 台湾省
-
ipList.add("61.186.76.165");// 湖南省怀化市 电信
-
ipList.add("221.202.127.39");// 辽宁省葫芦岛市 联通
-
ipList.add("114.252.45.210");// 北京市北京市 联通
-
ipList.add("127.0.0.1");// 未分配或者内网
-
ipList.add("192.168.10.170");// 未分配或者内网
-
ipList.add("132.191.25.116:8080");// 辽宁省葫芦岛市
-
for (int i = 0; i < ipList.size(); i++) {
-
String ip = ipList.get(i);
-
String addresses = IPUtils.getAddresses(ip);
-
System.out.println(ip + "==" + addresses);
-
}
-
System.err.println("\r\n\r\n***************************\r\n\r\n睡5秒\r\n\r\n***************************\r\n\r\n");
-
try {
-
Thread.sleep(5000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
for (int j = 63; j < 266; j += 63) {
-
for (int k = 0; k < 266; k += 19) {
-
for (int m = 0; m < 266; m += 13) {
-
String ip = "60." + j + "." + k + "." + m;
-
String address1 = IPUtils.getAddresses(ip);
-
System.out.println(ip + "==" + address1);
-
}
-
}
-
}
-
}
-
}
代码整完了,问题也解决了……
说明一下,
我最开始获取客户端地址,用的是在前端页面引入“http://ip.ws.126.net/ipquery”接口,
但此接口只支持js,无法写到Java后台去,
项目从http转https后该接口边便失效,又找不到https协议的ip查询接口,
因此只能在后台获取远程ip(LSB的话记得ip转换),便开始在后台使用淘宝的ip地址查询接口,
可是高频率访问时淘宝ip地址查询接口总是SocketTimeout,经过各种Httpclient优化无效,后来发现加上时间戳去缓存可以改善连接超时,
就这样用了一段时间后,频繁访问时还是会报SocketTimeoutException,
因此又调研了这许多接口,最终确定了三个比较高效、精确、稳定的接口,做成了多线程的方式随机访问。