ホームページ  >  記事  >  Java  >  Spring Boot が IP アドレス解決を迅速に実装する方法

Spring Boot が IP アドレス解決を迅速に実装する方法

PHPz
PHPz転載
2023-05-10 15:04:161305ブラウズ

はじめに:

ローカル IP 解決を使用する場合は、ip2region を使用します。このプロジェクトでは、より詳細なローカル IP アドレス対応表が維持されています。オフライン環境で使用したい場合は、インポートする必要がありますこのプロジェクトのバージョンに応じて、指定方法が異なる場合があります。

<!--    ip库-->
<dependency>
	<groupId>org.lionsoul</groupId>
	<artifactId>ip2region</artifactId>
	<version>2.6.3</version>
        </dependency>

開発:

xdb ファイルを使用する場合は、プロジェクト ファイル ディレクトリにダウンロードする必要があります。ip2region を使用して完全に xdb ファイルに基づいてクエリを実行したとしても、単一クエリは 10 マイクロ秒のレベルです。メモリ アクセラレーション クエリは次の 2 つの方法で有効にできます:

  • vインデックス インデックス キャッシュ: ベクトル インデックス データをキャッシュするために固定の 512KiB メモリ空間を使用します。 、1 つの IO ディスク操作を削減し、平均クエリ効率を維持します。10 ~ 20 マイクロ秒の間で安定しています。

  • xdb 全体ファイル キャッシュ: xdb ファイル全体をメモリにロードします。メモリ使用量は xdb ファイルのサイズと同じです。ディスク IO 操作はなく、マイクロ秒レベルのクエリ効率はありません。維持されています。

/**
 * ip查询
 */
@Slf4j
public class IPUtil {
    private static final String UNKNOWN = "unknown";
    protected IPUtil(){ }
    /**
     * 获取 IP地址
     * 使用 Nginx等反向代理软件, 则不能通过 request.getRemoteAddr()获取 IP地址
     * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,
     * X-Forwarded-For中第一个非 unknown的有效IP字符串,则为真实IP地址
     */
    public static String getIpAddr(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 "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
    public static  String getAddr(String ip){
        String dbPath = "src/main/resources/ip2region/ip2region.xdb";
        // 1、从 dbPath 加载整个 xdb 到内存。
        byte[] cBuff;
        try {
            cBuff = Searcher.loadContentFromFile(dbPath);
        } catch (Exception e) {
            log.info("failed to load content from `%s`: %s\n", dbPath, e);
            return null;
        }
        // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
        Searcher searcher;
        try {
            searcher = Searcher.newWithBuffer(cBuff);
        } catch (Exception e) {
           log.info("failed to create content cached searcher: %s\n", e);
            return null;
        }
        // 3、查询
        try {
            String region = searcher.searchByStr(ip);
            return region;
        } catch (Exception e) {
            log.info("failed to search(%s): %s\n", ip, e);
        }
        return null;
    }

ここでは、IP 解決と IP アドレス解決を取得する 2 つのメソッドを含む、IP 解決をツール クラスにカプセル化します。IP 解決はリクエストで取得できます。 IP を取得した後、その IP に基づいて xdb で対応する IP アドレスの解決を見つける必要があります。ローカル データベースには特定の欠陥がある可能性があるため、一部の IP は解決できません。

オンライン分析:

より包括的な IP アドレス情報を取得したい場合は、オンライン データベースを使用できます。ここで提供されるのは、whois.pconline.com の IP 分析です。分析は私の中にあります。使用中のパフォーマンスは非常にスムーズで、解決できない IP はほんのわずかです。

@Slf4j
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 String getRealAddressByIP(String ip) {
        String address = UNKNOWN;
        // 内网不查询
        if (IpUtils.internalIp(ip)) {
            return "内网IP";
        }
        if (true) {
            try {
                String rspStr = sendGet(IP_URL, "ip=" + ip + "&json=true" ,"GBK");
                if (StrUtil.isEmpty(rspStr)) {
                    log.error("获取地理位置异常 {}" , ip);
                    return UNKNOWN;
                }
                JSONObject obj = JSONObject.parseObject(rspStr);
                String region = obj.getString("pro");
                String city = obj.getString("city");
                return String.format("%s %s" , region, city);
            } catch (Exception e) {
                log.error("获取地理位置异常 {}" , ip);
            }
        }
        return address;
    }
    public static String sendGet(String url, String param, String contentType) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            log.info("sendGet - {}" , urlNameString);
            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);
            }
            log.info("recv - {}" , result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }
}

シナリオ:

それでは、開発のどのプロセスで IP アドレスを取得するのがより適切なのでしょうか? ここではインターセプターを使用します。サービスに入るすべてのリクエストをインターセプトし、事前操作を実行し、サービスに入るときにリクエスト ヘッダーの解析、IP 取得、IP アドレス解決を完了します。これにより、IP アドレスとその他の情報が後続のすべてのプロセスで再利用できるようになります。

あーるーるーるーるーるー

以上がSpring Boot が IP アドレス解決を迅速に実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。