首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 根據 IP 地址獲取地理位置:騰訊/新浪/淘寶 API 實戰對比

     編輯:Java 相關知識

需求背景

網站後台需解析用戶 IP 歸屬地理位置(國家、省份、城市),用於訪問統計、風控攔截、內容分發等場景。本文對比三大主流免費 API 並提供生產級封裝代碼。

主流 API 對比

服務商接口地址返回格式頻率限制特點
騰訊 IP 分享計劃https://ip.qq.com/cgi-bin/searchip?searchip1=HTML 文本無官方說明中文友好、需解析 HTML
新浪 IP 查詢https://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=JSON較寬鬆結構化、支持 JSONP
淘寶 IP 庫https://ip.taobao.com/service/getIpInfo.php?ip=JSONQPS 限制數據準確、官方維護

核心實現:騰訊 API 解析版

public class IpLocationService {
    private static final String QQ_IP_API = "https://ip.qq.com/cgi-bin/searchip?searchip1=";
    
    public String getAddressByIP(String ip) {
        if (ip == null || ip.trim().isEmpty()) {
            return "無效 IP";
        }
        
        try {
            URL url = new URL(QQ_IP_API + URLEncoder.encode(ip, "UTF-8"));
            URLConnection conn = url.openConnection();
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(5000);
            
            // 響應編碼為 GBK
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "GBK"))) {
                
                StringBuilder result = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
                
                return parseQQResponse(result.toString());
            }
        } catch (IOException e) {
            return "查詢失敗: " + e.getMessage();
        }
    }
    
    private String parseQQResponse(String html) {
        // 響應包含: "該IP地址為:廣東省廣州市 騰訊計算機系統有限公司"
        String prefix = "該IP地址為:";
        int start = html.indexOf(prefix);
        if (start == -1) return "解析失敗";
        
        start += prefix.length();
        int end = html.indexOf(" ", start);
        if (end == -1) end = html.length();
        
        String location = html.substring(start, end).trim();
        
        // 進一步拆分省市
        String province = "";
        String city = "";
        int provinceEnd = location.indexOf("省");
        if (provinceEnd != -1) {
            province = location.substring(0, provinceEnd + 1);
            int cityEnd = location.indexOf("市", provinceEnd);
            if (cityEnd != -1) {
                city = location.substring(provinceEnd + 1, cityEnd + 1);
            }
        }
        
        return String.format("省份: %s, 城市: %s, 完整: %s", province, city, location);
    }
}

進階版:新浪 JSON API(推薦)

public class SinaIpLocationService {
    private static final String SINA_API = "https://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=";
    
    public IpLocation getLocation(String ip) {
        String urlStr = SINA_API + ip;
        try (InputStream is = new URL(urlStr).openStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
            
            StringBuilder json = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) json.append(line);
            
            // 簡單 JSON 解析(生產環境建議用 Jackson/Gson)
            String jsonStr = json.toString();
            // 格式: {"ret":1,"start":"...","end":"...","country":"中國","province":"廣東","city":"廣州","district":"","isp":"","type":"","desc":""}
            
            IpLocation loc = new IpLocation();
            loc.setCountry(extractJsonValue(jsonStr, "country"));
            loc.setProvince(extractJsonValue(jsonStr, "province"));
            loc.setCity(extractJsonValue(jsonStr, "city"));
            loc.setIsp(extractJsonValue(jsonStr, "isp"));
            loc.setRawJson(jsonStr);
            return loc;
        } catch (IOException e) {
            throw new RuntimeException("新浪 IP 查詢失敗", e);
        }
    }
    
    private String extractJsonValue(String json, String key) {
        String pattern = "\"" + key + "\":\"";
        int start = json.indexOf(pattern);
        if (start == -1) return "";
        start += pattern.length();
        int end = json.indexOf("\"", start);
        return end > start ? json.substring(start, end) : "";
    }
    
    public static class IpLocation {
        private String country, province, city, isp, rawJson;
        // Getter/Setter/toString...
    }
}

生產級封裝:多源容錯、緩存、異步

@Service
public class ProductionIpLocationService {
    private final List providers = Arrays.asList(
        new SinaIpLocationProvider(),
        new TaobaoIpLocationProvider(),
        new QqIpLocationProvider()
    );
    
    private final Cache cache = Caffeine.newBuilder()
        .maximumSize(10000)
        .expireAfterWrite(Duration.ofHours(24))
        .build();
    
    @Async
    public CompletableFuture getLocationAsync(String ip) {
        return CompletableFuture.supplyAsync(() -> getLocation(ip));
    }
    
    public IpLocation getLocation(String ip) {
        // 1. 緩存查找
        IpLocation cached = cache.getIfPresent(ip);
        if (cached != null) return cached;
        
        // 2. 多源嘗試
        for (IpLocationProvider provider : providers) {
            try {
                IpLocation loc = provider.getLocation(ip);
                if (loc != null && loc.isValid()) {
                    cache.put(ip, loc);
                    return loc;
                }
            } catch (Exception e) {
                log.warn("Provider {} 失敗: {}", provider.getClass().getSimpleName(), e.getMessage());
            }
        }
        
        return IpLocation.unknown(ip);
    }
    
    interface IpLocationProvider {
        IpLocation getLocation(String ip);
    }
}

關鍵最佳實踐

  1. 超時控制:連接 3s、讀取 5s,防止阻塞業務線程
  2. 編碼處理:騰訊 API 返回 GBK,新浪/淘寶 UTF-8
  3. 緩存策略:IP 歸屬地相對穩定,24h 過期、萬級容量
  4. 熔斷降級:單源失敗快速切換、記錄指標
  5. 異步非阻塞:@Async + CompletableFuture,不阻塞主流程
  6. 隱私合規:僅存儲脫敏 IP、位置信息,遵循 GDPR/個信法

離線數據庫方案(高併發/內網)

  • MaxMind GeoIP2:商業級、MMDB 格式、Java API 高性能
  • ip2region:國產開源、B 树/內存雙模式、微秒級查詢
  • 部署方式:應用啟動加載到堆外內存、定期熱更新

總結

IP 地理位置查詢推薦優先使用新浪/淘寶 JSON API,結合緩存、異步、多源容錯構建生產級服務。高併發/內網場景建議採用離線數據庫(ip2region/MaxMind)消除網絡依賴、實現微秒級查詢。關鍵在於:超時控制、編碼正確、緩存命中率、熔斷機制、合規脫敏。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved