1. 程式人生 > >java web獲取客戶端外網ip和所在區域

java web獲取客戶端外網ip和所在區域

@參考文章1@參考文章2@參考文章3@參考文章4,@之前同事的專案

 controller

@Controller
@RequestMapping("/home")
public class HomeController {
    @RequestMapping("/")
    public String index(HttpServletRequest req) {
        try {
            String ip = IpUtil.getOuterNetIp(req);//獲取外網ip
            System.out.println(ip);
            String ipCity 
= IpUtil.getIpArea(ip);//根據外網ip獲取所在區域 System.out.println(ipCity); req.setAttribute("ipCity", ipCity); } catch (Exception e) { e.printStackTrace(); } return "home"; } }
View Code

IpUtil

import java.io.BufferedReader;
import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils; import org.json.JSONException; import org.json.JSONObject; import sun.net.util.IPAddressUtil; /** * @todo ip工具類 * @author yanan * @date 2018年11月12日 */ public class IpUtil { /** * @todo 獲取外網ip所在區域 * @param * @date 2018年11月12日 * @author yanan */ public static String getIpArea(String ip) throws Exception { // 淘寶的ip定位 JSONObject json = readJsonFromUrl("http://ip.taobao.com/service/getIpInfo.php?ip=" + ip); if (json.has("code")) { if ((json.get("code").toString().trim()).equalsIgnoreCase("0")) { String strIp = ((JSONObject) json.get("data")).get("city").toString(); return strIp; } else { return "鄭州"; } } else { return "鄭州"; } } /** * @todo 百度api ip介面 * @param * @date 2018年11月9日 * @author yanan */ public static JSONObject readJsonFromUrl(String url) throws Exception, JSONException { InputStream is = null; try { URL ul = new URL(url); // 建立 URL HttpURLConnection urlCon = (HttpURLConnection) ul.openConnection(); urlCon.setConnectTimeout(2000); urlCon.setReadTimeout(2000); // Long b = System.currentTimeMillis(); is = urlCon.getInputStream(); // 開啟到這個URL的流 // System.out.println("獲取百度api // ip介面:="+(System.currentTimeMillis()-b)); BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8"))); String jsonText = readAll(rd); JSONObject json = new JSONObject(jsonText); return json; } catch (Exception e) { e.printStackTrace(); JSONObject jsonObj = new JSONObject(); jsonObj.put("status", "1"); // System.out.println("new jsonObj status=0,new jsonObj status=0new // jsonObj status=0new jsonObj status=0"); return jsonObj; } finally { if (null != is) is.close(); } } /** * @todo 將輸入流轉換成字串 * @param * @date 2018年11月9日 * @author yanan */ private static String readAll(Reader rd) throws IOException { StringBuilder sb = new StringBuilder(); int cp; while ((cp = rd.read()) != -1) { sb.append((char) cp); } return sb.toString(); } /** * @todo 獲取外網ip * @param * @date 2018年11月12日 * @author yanan * @throws Exception */ public static String getOuterNetIp(final HttpServletRequest request) throws Exception { String ipAddr = getIpAddr(request);//獲取ip地址 boolean internalIp = internalIp(ipAddr);//判斷ip是否內網ip if(!internalIp){//外網地址直接返回 return ipAddr; } String result = ""; URLConnection connection; BufferedReader in = null; try { URL url = new URL("http://www.icanhazip.com"); connection = url.openConnection(); connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "KeepAlive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); connection.setConnectTimeout(3000); connection.setReadTimeout(3000); connection.connect(); in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (MalformedURLException e) { } catch (IOException e) { } finally { try { if (in != null) { in.close(); } } catch (IOException e) { } } return result; } /** * @todo 判斷是否內網ip * @param * @date 2018年11月12日 * @author yanan */ public static boolean internalIp(String ip) { if ("127.0.0.1".equalsIgnoreCase(ip)) return true; if ("0:0:0:0:0:0:0:1".equals(ip)) return true; byte[] addr = IPAddressUtil.textToNumericFormatV4(ip); return internalIp(addr); } /** * @todo 判斷解析後的ip是否內網 * @param * @date 2018年11月12日 * @author yanan */ public static boolean internalIp(byte[] addr) { 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; // 127.0.0.1/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: switch (b1) { case SECTION_6: return true; } default: return false; } } /** * @todo 獲取ip地址 * @param * @date 2018年11月12日 * @author yanan */ public static final String getIpAddr(final HttpServletRequest request) throws Exception { if (request == null) { throw (new Exception("======================request為null======================")); } /** * 在JSP裡,獲取客戶端的IP地址的方法是:request.getRemoteAddr() * 這種方法在大部分情況下都是有效的。但是在通過了Apache,Squid等反向代理軟體就不能獲取到客戶端的真實IP地址了。 * 經過代理以後,由於在客戶端和服務之間增加了中間層,因此伺服器無法直接拿到客戶端的IP,伺服器端應用也無法直接通過 * 轉發請求的地址返回給客戶端。但是在轉發請求的HTTP頭資訊中,增加了X-FORWARDED-FOR等資訊。用以跟蹤原有的客戶 * 端IP地址和原來客戶端請求的伺服器地址。 * 假定客戶端通過多級代理,最終到達伺服器端(nginx,squid,haproxy);此時經過多級反向的代理, * 通過方法getRemoteAddr(),得不到客戶端真實IP,可以通過x-forwarded-for等獲得轉發後請求資訊。 * 因此獲取ip的步驟應為:先獲取各種代理伺服器ip,若為空再獲取request.getRemoteAddr() */ //x-forwarded-for是一個 Squid 開發的欄位,只有在通過了HTTP代理或者負載均衡伺服器時才會新增該項。當客戶端請求被轉發, //格式為X-Forwarded-For:client1,proxy1,proxy2,一般情況下,第一個ip為客戶端真實ip, //IP將會追加在其後並以逗號隔開,後面的為經過的代理伺服器ip。現在大部分的代理都會加上這個請求頭。 String ipString = request.getHeader("x-forwarded-for"); //用apache http做代理時一般會加上Proxy-Client-IP請求頭 if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) { ipString = request.getHeader("Proxy-Client-IP"); } //WL-Proxy-Client-IP是他的weblogic外掛加上的頭。 if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) { ipString = request.getHeader("WL-Proxy-Client-IP"); } //HTTP_CLIENT_IP :有些代理伺服器會加上此請求頭。 if (ipString == null || ipString.length() == 0 || "unknown".equalsIgnoreCase(ipString)) { ipString = request.getHeader("HTTP_CLIENT_IP"); System.out.println("HTTP_CLIENT_IP ipString: " + ipString); } if (ipString == null || ipString.length() == 0 || "unknown".equalsIgnoreCase(ipString)) { ipString = request.getHeader("HTTP_X_FORWARDED_FOR"); System.out.println("HTTP_X_FORWARDED_FOR ipString: " + ipString); } //nginx代理一般會加上此請求頭。 if (ipString == null || ipString.length() == 0 || "unknown".equalsIgnoreCase(ipString)) { ipString = request.getHeader("X-Real-IP"); System.out.println("X-Real-IP ipString: " + ipString); } //當不是上述(代理)方式訪問時,request.getRemoteAddr()直接獲取客戶真實ip if (StringUtils.isBlank(ipString) || "unknown".equalsIgnoreCase(ipString)) { ipString = request.getRemoteAddr(); //客戶端未經過代理,直接訪問伺服器端(nginx,squid,haproxy); } // 多個路由時,取第一個非unknown的ip final String[] arr = ipString.split(","); for (final String str : arr) { if (!"unknown".equalsIgnoreCase(str)) { ipString = str; break; } } return ipString; } }
View Code