目前国内各大应用几乎都有显示用户的ip归属地,包括本站也会有显示相关的ip归属地,如下图:
那么这个获取归属地怎么弄呢?其实方法很简单,我们可以直接借助开源的ip归属地来使用即可。
这里我们借助的工具是:
http://whois.pconline.com.cn/ipJson.jsp
当我们访问这个地址的时候就会获取到对应的归属地,如下图:
我们只需要解析上面的地址即可。
本文我们使用java实战演示下通过这个工具获取用户的ip地址。
1、获取ip
首先我们需要从nginx中获取到用户真实的ip,然后传递给咱们得应用,最后在应用里面获取到用户请求的ip地址,示例代码如下:
public class IpUtil { private static final String UNKNOWN = "unknown"; private static final String HEADER_FORWARDED = "x-forwarded-for"; private static final String HEADER_PROXY = "Proxy-Client-IP"; private static final String HEADER_WL_PROXY = "WL-Proxy-Client-IP"; private static final String HEADER_HTTP = "HTTP_CLIENT_IP"; private static final String HEADER_HTTP_FORWARDED = "HTTP_X_FORWARDED_FOR"; private static final String LOCAL_IP = "127.0.0.1"; private static final String LOCAL_HOST = "localhost"; /** * 获取 IP 地址 * * @param request * @return */ public String getIpAddr(HttpServletRequest request) { String ip = request.getHeader(HEADER_FORWARDED); if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader(HEADER_PROXY); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader(HEADER_WL_PROXY); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader(HEADER_HTTP); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader(HEADER_HTTP_FORWARDED); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } // 本机访问 if (LOCAL_IP.equalsIgnoreCase(ip) || LOCAL_HOST.equalsIgnoreCase(ip) || "0:0:0:0:0:0:0:1".equalsIgnoreCase(ip)) { // 根据网卡取本机配置的 IP try { InetAddress localHost = InetAddress.getLocalHost(); ip = localHost.getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } } // 对于通过多个代理的情况,第一个 IP 为客户端真实 IP,多个 IP 按照','分割 if (ip != null && ip.length() > 15) { if (ip.indexOf(",") > 15) { ip = ip.substring(0, ip.indexOf(",")); } } return ip; } }
2、获取ip归属地
接下来我们就要用获取到的ip去请求工具,获取用户的ip归属地。示例代码如下:
import com.alibaba.fastjson.JSONObject; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; public class AddressUtils { // IP地址查询 public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; // 未知地址 public static final String UNKNOWN = "XX XX"; public static void main(String[] args) { System.out.println(getRealAddressByIP("218.88.83.8")); } public static String getRealAddressByIP(String ip) { // 内网不查询 if (internalIp(ip)) { return "内网IP"; } try { String rspStr = sendGet(IP_URL, "ip=" + ip + "&json=true", "GBK"); if ("".equals(rspStr)) { return UNKNOWN; } JSONObject obj = JSONObject.parseObject(rspStr); return obj.toJSONString(); } catch (Exception e) { e.printStackTrace(); } return UNKNOWN; } public static boolean internalIp(String ip) { byte[] addr = textToNumericFormatV4(ip); return internalIp(addr) || "127.0.0.1".equals(ip); } private static boolean internalIp(byte[] addr) { if (addr == null || addr.length < 2) { return true; } final byte b0 = addr[0]; final byte b1 = addr[1]; // 10.x.x.x/8 final byte SECTION_1 = 0x0A; // 172.16.x.x/12 final byte SECTION_2 = (byte) 0xAC; final byte SECTION_3 = (byte) 0x10; final byte SECTION_4 = (byte) 0x1F; // 192.168.x.x/16 final byte SECTION_5 = (byte) 0xC0; final byte SECTION_6 = (byte) 0xA8; switch (b0) { case SECTION_1: return true; case SECTION_2: if (b1 >= SECTION_3 && b1 <= SECTION_4) { return true; } case SECTION_5: if (b1 == SECTION_6) { return true; } default: return false; } } /** * 将IPv4地址转换成字节 * * @param text IPv4地址 * @return byte 字节 */ public static byte[] textToNumericFormatV4(String text) { if (text.length() == 0) { return null; } byte[] bytes = new byte[4]; String[] elements = text.split("\\.", -1); try { long l; int i; switch (elements.length) { case 1: l = Long.parseLong(elements[0]); if ((l < 0L) || (l > 4294967295L)) { return null; } bytes[0] = (byte) (int) (l >> 24 & 0xFF); bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 2: l = Integer.parseInt(elements[0]); if ((l < 0L) || (l > 255L)) { return null; } bytes[0] = (byte) (int) (l & 0xFF); l = Integer.parseInt(elements[1]); if ((l < 0L) || (l > 16777215L)) { return null; } bytes[1] = (byte) (int) (l >> 16 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 3: for (i = 0; i < 2; ++i) { l = Integer.parseInt(elements[i]); if ((l < 0L) || (l > 255L)) { return null; } bytes[i] = (byte) (int) (l & 0xFF); } l = Integer.parseInt(elements[2]); if ((l < 0L) || (l > 65535L)) { return null; } bytes[2] = (byte) (int) (l >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 4: for (i = 0; i < 4; ++i) { l = Integer.parseInt(elements[i]); if ((l < 0L) || (l > 255L)) { return null; } bytes[i] = (byte) (int) (l & 0xFF); } break; default: return null; } } catch (NumberFormatException e) { return null; } return bytes; } /** * 向指定 URL 发送GET方法的请求 * * @param url 发送请求的 URL * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @param contentType 编码类型 * @return 所代表远程资源的响应结果 */ public static String sendGet(String url, String param, String contentType) { StringBuilder result = new StringBuilder(); BufferedReader in = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); URLConnection connection = realUrl.openConnection(); connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); connection.connect(); in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); String line; while ((line = in.readLine()) != null) { result.append(line); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); } } catch (Exception ex) { ex.printStackTrace(); } } return result.toString(); } }
我们通过这个工具类就可以获取到相关的IP归属地了。
备注:
1、这里主要是演示,所以直接使用urlconnection进行http请求了,真实环境中需要对此模块进行改造,例如使用httpclient或者okhttp等现成的工具。
还没有评论,来说两句吧...