主要依赖:
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>org.lionsoul</groupId> <artifactId>ip2region</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency>
|
首先先获取到访问者的ip地址
访问必须是通过公网访问,要是内网互ip访问相测试的话,会返回127.0.0.1,或者访问者的内网ip地址。
通过X-FORWARDED-FOR等信息。跟踪原有的客户端IP地址和原来客户端请求的服务器地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
| package com.wonder.utils;
import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException;
public class getIPutils { public static String resClientIP(HttpServletRequest request) { String ip = getClientIpAddress(request); boolean isInner = isInnerIP(ip); if (!isInner) { return ip; }else { return "内网ip"; }
} public static String getClientIpAddress(HttpServletRequest request) { String headerName = "x-forwarded-for"; String ip = request.getHeader(headerName); if (null != ip && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) { if (ip.indexOf(",") != -1) { ip = ip.split(",")[0]; } } if (checkIp(ip)) { headerName = "Proxy-Client-IP"; ip = request.getHeader(headerName); } if (checkIp(ip)) { headerName = "WL-Proxy-Client-IP"; ip = request.getHeader(headerName); } if (checkIp(ip)) { headerName = "HTTP_CLIENT_IP"; ip = request.getHeader(headerName); } if (checkIp(ip)) { headerName = "HTTP_X_FORWARDED_FOR"; ip = request.getHeader(headerName); } if (checkIp(ip)) { headerName = "X-Real-IP"; ip = request.getHeader(headerName); } if (checkIp(ip)) { headerName = "remote addr"; ip = request.getRemoteAddr(); if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) { InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ip = inet.getHostAddress(); } } System.out.println("getClientIp IP is " + ip + ", headerName = " + headerName); return ip; } private static boolean checkIp(String ip) { if (null == ip || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { return true; } return false; }
public static boolean isInnerIP(String ipAddress) { boolean isInnerIp; long ipNum = getIpNum(ipAddress);
long aBegin = getIpNum("10.0.0.0"); long aEnd = getIpNum("10.255.255.255");
long bBegin = getIpNum("172.16.0.0"); long bEnd = getIpNum("172.31.255.255");
long cBegin = getIpNum("192.168.0.0"); long cEnd = getIpNum("192.168.255.255"); isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || ipAddress.equals("127.0.0.1"); return isInnerIp; }
private static long getIpNum(String ipAddress) { String[] ip = ipAddress.split("\\."); long a = Integer.parseInt(ip[0]); long b = Integer.parseInt(ip[1]); long c = Integer.parseInt(ip[2]); long d = Integer.parseInt(ip[3]);
return a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d; }
private static boolean isInner(long userIp, long begin, long end) { return (userIp >= begin) && (userIp <= end); }
public static String getRealIP(HttpServletRequest request){ String clientIp = request.getHeader("x-forwarded-for");
if (clientIp == null || clientIp.length() == 0 || "unknown".equalsIgnoreCase(clientIp)) { clientIp = request.getRemoteAddr(); }
String[] clientIps = clientIp.split(","); if(clientIps.length <= 1) return clientIp.trim();
if(isComefromCDN(request)){ if(clientIps.length>=2) return clientIps[clientIps.length-2].trim(); }
return clientIps[clientIps.length-1].trim(); }
private static boolean isComefromCDN(HttpServletRequest request) { String host = request.getHeader("host"); return host.contains("www.189.cn") ||host.contains("shouji.189.cn") || host.contains( "image2.chinatelecom-ec.com") || host.contains( "image1.chinatelecom-ec.com"); }
}
|
相关请求头
X-Forwarded-For
记录一个请求从客户端出发到目标服务器过程中经历的代理,或者负载平衡设备的IP。这是由缓存代理软件 Squid 引入,用来表示 HTTP 请求端真实 IP,现在已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。格式为X-Forwarded-For:client1,proxy1,proxy2,一般情况下,第一个ip为客户端真实ip,后面的为经过的代理服务器的ip。现在大部分的代理都会加上这个请求头。
Proxy-Client-IP/WLProxy-Client-IP
这个一般是经过apache http服务器的请求才会有,用apache http做代理时一般会加上Proxy-Client-IP请求头,而WL-Proxy-Client-IP是他的weblogic插件加上的头。
HTTP_CLIENT_IP
有些代理服务器会加上此请求头。
X-Real-IP nginx
代理一般会加上此请求头。
通过ip获取位置
通过上面返还的ip地址进行解析,具体方式可以参考Ip2region的官方文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| package com.wonder.utils;
import com.alibaba.fastjson.JSONObject; import org.lionsoul.ip2region.xdb.Searcher; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit;
public class FromIpToCtiy { public static String resLocation(String ip) { String dbPath = "src/main/resources/ip2region.xdb"; byte[] vIndex; try { vIndex = Searcher.loadVectorIndexFromFile(dbPath); } catch (Exception e) { System.out.printf("failed to load vector index from `%s`: %s\n", dbPath, e); return "{\"error\":\"加载索引失败\"}"; }
Searcher searcher; try { searcher = Searcher.newWithVectorIndex(dbPath, vIndex); } catch (Exception e) { System.out.printf("failed to create vectorIndex cached searcher with `%s`: %s\n", dbPath, e); return "{\"error\":\"创建缓存搜索器失败\"}"; } long sTime; String region = null; long cost = 0; try { sTime= System.nanoTime(); region= searcher.search(ip); cost= TimeUnit.NANOSECONDS.toMicros((long) (System.nanoTime() - sTime)); System.out.printf("{region: %s, ioCount: %d, took: %d μs}\n", region, searcher.getIOCount(), cost); searcher.close(); } catch (Exception e) { System.out.printf("failed to search(%s): %s\n", ip, e); } Map<String,String> resmap = new HashMap<>(); resmap.put("location",region); resmap.put("ioCount", String.valueOf(searcher.getIOCount())); resmap.put("cost", cost+"μs"); return JSONObject.toJSONString(resmap); } }
|
说实在的,其实没啥技术含量,就是互相调用查看的,通过客户端的请求进行解析。然后查询地址的,也就是通过一个人家写的库进行查询。很简单的。欸。。目前没啥好想法了。