Java obtiene la atribución correspondiente en base a la dirección IP

1. Introducción

Recientemente, las principales plataformas han agregado la función de mostrar la dirección IP del orador en el área de comentarios, como Bilibili, Weibo, Zhihu, etc. A continuación, hablemos sobre cómo obtener la dirección IP en Java.

2 Obtener la dirección IP

Hay muchas formas de obtener una dirección IP en Java, por lo que no las presentaré una por una. El método más utilizado para obtener una dirección IP se proporciona solo como referencia. El código es el siguiente:

@Slf4j
public class IpUtils {
    
    

    /**
     * 获取ip地址
     * @param request request对象
     * @return 返回对应IP地址
     */
    public static String getIpAddress(HttpServletRequest request){
    
    
        String ipAddress = null;
        try {
    
    
            ipAddress = request.getHeader("X-Forwarded-For");
            if (ipAddress != null && ipAddress.length() != 0 && !"unknown".equalsIgnoreCase(ipAddress)) {
    
    
                // 多次反向代理后会有多个ip值,第一个ip才是真实ip
                if (ipAddress.contains(",")) {
    
    
                    ipAddress = ipAddress.split(",")[0];
                }
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
    
    
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
    
    
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
    
    
                ipAddress = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
    
    
                ipAddress = request.getRemoteAddr();
            }
        }catch (Exception e) {
    
    
            log.error("IPUtils ERROR ",e);
        }
        return ipAddress;
    }
    
    /**
     * 获取mac地址
     */
    public static String getMacAddress() throws Exception {
    
    
        // 取mac地址
        byte[] macAddressBytes = NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress();
        // 下面代码是把mac地址拼装成String
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < macAddressBytes.length; i++) {
    
    
            if (i != 0) {
    
    
                sb.append("-");
            }
            // mac[i] & 0xFF 是为了把byte转化为正整数
            String s = Integer.toHexString(macAddressBytes[i] & 0xFF);
            sb.append(s.length() == 1 ? 0 + s : s);
        }
        return sb.toString().trim().toUpperCase();
    }
    
}

Explique algunos sustantivos que aparecen aquí:

  • X-Forwarded-For : un encabezado de extensión HTTP, principalmente para que el servidor web obtenga la dirección IP real del usuario visitante. Para cada dirección IP, cada valor está separado por una coma + espacio. El más a la izquierda es la dirección IP del cliente original. Si hay varias capas de proxies en el medio, cada capa de proxies agregará la IP del cliente que se conecta a a X-Reenviado-Por la derecha.
  • Proxy-Client-IP : por lo general, solo está disponible a través de la solicitud del servidor Apache http. Cuando se usa Apache http como proxy, generalmente se agrega el encabezado de solicitud Proxy-Client-IP.
  • WL-Proxy-Client-IP : también es un encabezado agregado al complemento weblogic a través del servidor Apache http.
  • X-Real-IP : generalmente solo registra la IP real del cliente solicitante
  • HTTP_CLIENT_IP : encabezado HTTP enviado por el servidor proxy. Si se trata de un "proxy superanónimo", devuelve un valor de ninguno.

3 Introducción a Ip2region

3.1 99,9% de precisión

Los datos agregan los datos de algunos conocidos proveedores de consultas de IP para colocar nombres. Estos son sus índices oficiales de precisión. Después de las pruebas, son de hecho más precisos que el posicionamiento IP puro clásico.

Los datos de ip2region se agregan desde la API abierta o los datos de los siguientes proveedores de servicios (el programa de actualización solicita de 2 a 4 veces por segundo):

  • 01, >80 %, biblioteca de direcciones IP de Taobao, http://ip.taobao.com/%5C
  • 02,≈10%,GeoIP,https://geoip.com/%5C
  • 03, ≈2 %, biblioteca IP pura, http://www.cz88.net/%5C

Observaciones: Si las API abiertas o los datos mencionados anteriormente no están disponibles para datos abiertos, ip2region detendrá el servicio de actualización de datos.

3.2 Soporte al cliente de consultas múltiples

Los clientes integrados incluyen: java, C#, php, c, python, nodejs, extensión php (php5 y php7), golang, rust, lua, lua_c, nginx.
inserte la descripción de la imagen aquí

3.3 Características de Ip2region V2.0

3.3.1 Formato de datos estandarizados

La información de la región de cada segmento de datos IP tiene un formato fijo: País|Región|Provincia|Ciudad|ISP, solo la mayoría de los datos en China son precisos para la ciudad, y algunos datos en otros países solo se pueden ubicar en el país, y las opciones antes y después son todas 0.

3.3.2 Deduplicación y compresión de datos

El programa de generación de formato xdb deduplicará y comprimirá automáticamente algunos datos. Los datos IP predeterminados, la base de datos ip2region.xdb generada es de 11 MiB, y el tamaño de la base de datos aumentará gradualmente con el aumento de los detalles de los datos.

3.3.3 Respuesta de consulta extremadamente rápida

Incluso para consultas basadas completamente en archivos xdb, el tiempo de respuesta para una sola consulta es de diez microsegundos.

Puede habilitar las consultas aceleradas por memoria de las siguientes dos maneras:

  • Caché de índice vIndex: use un espacio de memoria fijo de 512 KiB para almacenar en caché datos de índice de vector, reducir una
    operación de disco de E/S y mantener la eficiencia de consulta promedio estable entre 10 y 20 microsegundos.
  • Caché de archivo completo xdb: cargue todo el archivo xdb en la memoria, el uso de la memoria es igual al tamaño del archivo xdb, no hay operaciones de E/S de disco y mantiene la eficiencia de las consultas en el nivel de microsegundos.

3.3.4 Respuesta de consulta extremadamente rápida

El xdb en formato v2.0 admite 100 millones de líneas de segmentos de datos IP de nivel, y la información de la región también se puede personalizar por completo. Por ejemplo, puede agregar datos para necesidades comerciales específicas en la región, tales como: Información de GPS/Uniforme internacional Código de Información Geográfica/Código Postal esperar. Es decir, puede usar ip2region para administrar sus propios datos de ubicación de IP.

4 Obtenga el archivo ip2region.xdb

¿Por qué desea obtener el archivo ip2region.xdb? Porque el dominio ip se basa en este archivo

4.1 Acceso directo

He empaquetado el archivo en Baidu Netdisk, los amigos pueden descargarlo directamente, la dirección es la siguiente:
Enlace: https://pan.baidu.com/s/1JSB0z2Cwl4umujKUzpBhFA
Código de extracción: 0zz5

4.2 Embalaje por su cuenta

Descargar proyecto:
Enlace: https://pan.baidu.com/s/1wHjUoHCmyH_PVcB9nf3cLw
Código de extracción: aq5y
Introduzca la carpeta de destino y ejecute el comando:

java -jar ip2region-maker-1.0.0.jar --src=./ip.merge.txt --dst=./ip2region.xdb

5 Utilice Ip2region V2.0 para obtener la provincia y ciudad correspondiente a través de la dirección IP

5.1 Tres algoritmos de consulta integrados

Todos los clientes de consulta tienen una única consulta a nivel de 0.x milisegundos, con tres algoritmos de consulta integrados.

  • algoritmo de memoria : toda la base de datos se carga en la memoria, y una sola consulta está dentro de 0.1x milisegundos, y la consulta única del cliente de lenguaje C está en el nivel de 0.00x milisegundos.
  • Algoritmo binario : basado en la búsqueda binaria, basado en el archivo ip2region.db, no necesita cargarse en la memoria y una sola consulta está al nivel de 0.x milisegundos.
  • Algoritmo b-tree : basado en el algoritmo btree, basado en el archivo ip2region.db, sin necesidad de cargar en la memoria, consulta de palabras a nivel de milisegundos 0.x, más rápido que el algoritmo binario.

5.2 Método de implementación específico

5.2.1 Introducir la dependencia de ip2region

<dependency>
    <groupId>org.lionsoul</groupId>
    <artifactId>ip2region</artifactId>
    <version>2.6.4</version>
</dependency>

5.2.2 archivo ip2region.xdb, colóquelo en el directorio de recursos del proyecto

inserte la descripción de la imagen aquí

5.2.3 Convertir la dirección IP del usuario basada completamente en el archivo ip2region.xdb

    /**
     * 获取ip属地(文件扫描)
     * @param ip IP地址
     * @return 返回地址
     */
    public static String getCityInfoByFile(String ip) {
    
    
        // 1、创建 searcher 对象
        String dbPath = "D:\\gitProject\\workRecord\\src\\main\\resources\\ip\\ip2region.xdb";
        Searcher searcher;
        try {
    
    
            searcher = Searcher.newWithFileOnly(dbPath);
        } catch (IOException e) {
    
    
            log.error("failed to create searcher with `{}`: ", dbPath, e);
            return null;
        }

        // 2、查询
        try {
    
    
            long sTime = System.nanoTime();
            String region = searcher.search(ip);
            long cost = TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - sTime);
            log.info("{region: {}, ioCount: {}, took: {} μs}", region, searcher.getIOCount(), cost);
            return region;
        } catch (Exception e) {
    
    
            log.info("failed to search({}): ", ip, e);
        }
        return null;
		// 3、备注:并发使用,每个线程需要创建一个独立的 searcher 对象单独使用。
    }

    public static void main(String[] args) throws Exception {
    
    
        getCityInfoByFile("111.0.72.130");
    }

producción:
inserte la descripción de la imagen aquí

5.2.4 Guarde en caché el índice VectorIndex y convierta la dirección IP del usuario

Podemos cargar los datos de VectorIndex desde el archivo xdb por adelantado y luego almacenarlos en caché globalmente.Usar el caché global de VectorIndex cada vez que se crea un objeto Searcher puede reducir una operación de E/S fija, acelerando así la consulta y reduciendo la presión de E/S.

    /**
     * 获取ip属地(缓存 VectorIndex 索引)
     * @param ip IP地址
     * @return 返回地址
     */
    public static String getCityInfoByVectorIndex(String ip) {
    
    
        String dbPath = "D:\\gitProject\\workRecord\\src\\main\\resources\\ip\\ip2region.xdb";
        // 1、从 dbPath 中预先加载 VectorIndex 缓存,并且把这个得到的数据作为全局变量,后续反复使用。
        byte[] vIndex;
        try {
    
    
            vIndex = Searcher.loadVectorIndexFromFile(dbPath);
        } catch (Exception e) {
    
    
            log.error("failed to load vector index from `{}`: ", dbPath, e);
            return null;
        }

        // 2、使用全局的 vIndex 创建带 VectorIndex 缓存的查询对象。
        Searcher searcher;
        try {
    
    
            searcher = Searcher.newWithVectorIndex(dbPath, vIndex);
        } catch (Exception e) {
    
    
            log.error("failed to create vectorIndex cached searcher with `{}`: ", dbPath, e);
            return null;
        }

        // 3、查询
        try {
    
    
            long sTime = System.nanoTime();
            String region = searcher.search(ip);
            long cost = TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - sTime);
            log.info("{region: {}, ioCount: {}, took: {} μs}\n", region, searcher.getIOCount(), cost);
            return region;
        } catch (Exception e) {
    
    
            log.error("failed to search({}): ", ip, e);
        }
        return null;
		// 备注:每个线程需要单独创建一个独立的 Searcher 对象,但是都共享全局的制度 vIndex 缓存。
    }

    public static void main(String[] args) throws Exception {
    
    
        getCityInfoByVectorIndex("111.0.72.130");
    }

producción:
inserte la descripción de la imagen aquí

5.2.5 Guarde en caché todos los datos de xdb y convierta la dirección IP del usuario

También podemos precargar todos los datos de ip2region.xdb en la memoria y luego crear un objeto de consulta basado en estos datos para implementar una consulta completamente basada en archivos, similar a la búsqueda de memoria anterior.

    /**
     * 获取ip属地(缓存整个 xdb 数据)
     * @param ip IP地址
     * @return 返回地址
     */
    public static String getCityInfoByMemorySearch(String ip) {
    
    
        String dbPath = "D:\\gitProject\\workRecord\\src\\main\\resources\\ip\\ip2region.xdb";

        // 1、从 dbPath 加载整个 xdb 到内存。
        byte[] cBuff;
        try {
    
    
            cBuff = Searcher.loadContentFromFile(dbPath);
        } catch (Exception e) {
    
    
            log.error("failed to load content from `{}`: ", dbPath, e);
            return null;
        }

        // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
        Searcher searcher;
        try {
    
    
            searcher = Searcher.newWithBuffer(cBuff);
        } catch (Exception e) {
    
    
            log.error("failed to create content cached searcher: ", e);
            return null;
        }

        // 3、查询
        try {
    
    
            long sTime = System.nanoTime();
            String region = searcher.search(ip);
            long cost = TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - sTime);
            log.info("{region: {}, ioCount: {}, took: {} μs}\n", region, searcher.getIOCount(), cost);
        } catch (Exception e) {
    
    
            log.error("failed to search({}): ", ip, e);
        }
        return null;
        // 备注:并发使用,用整个 xdb 数据缓存创建的查询对象可以安全的用于并发,也就是你可以把这个 searcher 对象做成全局对象去跨线程访问。
    }

    public static void main(String[] args) throws Exception {
    
    
        getCityInfoByMemorySearch("111.0.72.130");
    }

producción:
inserte la descripción de la imagen aquí

6 Resumen

Este es el final de la introducción para obtener la atribución correspondiente según la dirección IP. Los amigos que tengan preguntas pueden discutirlo en el área de comentarios.

Supongo que te gusta

Origin blog.csdn.net/qq_37284798/article/details/130005988
Recomendado
Clasificación