--- title: IP 属地是怎么查出来的?本地查询与在线查询方案对比 published: 2026-08-07T12:00:00 updated: 2026-08-07 description: 科普 IP 属地查询的原理:IP 段与归属地的映射、纯本地离线查询为何能做到毫秒级,并对比 ip2region、在线 API 与 MaxMind 三种方案的优劣与适用场景。 tags: ['IP', '网络', '科普'] draft: false difficulty: 入门 --- ## 写在前面 很多网站会在「登录记录」「安全中心」里显示你的登录 IP 归属地,比如「福建·福州 · 中国移动」。你可能好奇过:**服务器是怎么根据一个 IP 就判断出我在哪个城市、哪个运营商的?** 这篇科普文章讲清楚三件事: 1. IP 属地到底查的是什么; 2. 纯本地查询为什么能做到毫秒级且不联网; 3. 几种主流查询方案的优缺点对比,方便你按场景选型。 > 说明:文中用到的 IP 均为 RFC 5737 保留的文档示例段(TEST-NET-2,`198.51.100.0/24`),不会对应任何真实地址。 ## 先想清楚:IP 属地查的是什么 一个常见误区是「每个 IP 对应一个具体地址」。实际上 IP 属地的本质是 **IP 段与归属地的映射**。 运营商和机构在申请 IP 时,是按**网段(CIDR)**成块分配的。比如 `198.51.100.0/24` 这一个段,一整块都归属同一地区、同一运营商。所以归属地数据天然可以**按段存储**: ```text IP 起始 IP 结束 归属地 ──────────────────────────────────────── 198.51.100.0 198.51.100.255 中国|福建|福州|移动 198.51.101.0 198.51.101.255 中国|浙江|杭州|电信 ``` 全球公网 IP 约有 42 亿个,但**网段只有几十万条**。正因为存的是「段」而不是「每个 IP」,完整的归属地数据文件才只有几 MB(ip2region 的 `.xdb` 约 11MB)。这是「本地离线查询」可行的第一前提。 所以,**IP 属地从来不是精确到街道的定位**,它返回的是段级的「省|市|运营商」粗粒度信息。 ## 纯本地查询的原理 以开源的 **ip2region** 为例,它的查询完全在本地完成,不联网、不请求第三方,几十微秒到毫秒级返回。 ### 第一步:把 IP 变成整数 以 `198.51.100.42` 为例,它会转成一个 32 位整数 `0xC633642A`。IP 的四个数字本质就是 4 个字节,拼起来就是一个整数,这一步没有任何玄学。 ### 第二步:二分查找 在按起始 IP 排序的段列表里做**二分查找**,找到满足 `段的起始IP ≤ 目标整数 ≤ 段的结束IP` 的那一段。 二分查找的复杂度是 O(log N),N 是几十万条,所以很快——这就是「不靠网络也能毫秒返回」的核心。 ### 第三步:.xdb 文件的两级结构 ip2region 的 `.xdb` 不是简单顺序文件,内部分两个区,进一步加速: ```text ┌─────────────────────────────┐ │ 索引区 (Index) │ // 每段一条:startIP / endIP / 数据位置 │ …… 二分快速定位段 …… │ ├─────────────────────────────┤ │ 数据区 (Data) │ // 真正存放各段的地点字符串 │ …… │ └─────────────────────────────┘ ``` 先二分索引区定位到「是哪一段」,再按指针去数据区读出地点字符串,一次磁盘读就能拿到结果。 ### 为什么「离线数据」不会很快过期 IP 归属取决于**注册机构和运营商的分配**,一个网段通常长期稳定属于某地区、某运营商。所以: - 下载一次数据文件,可以用很久; - 归属偶尔变化时,**每月更新一次 `.xdb` 文件**即可(替换文件、不用重启服务); - 数据源来自 IANA/APNIC 等机构的分配表与公开归属信息,不是实时探测。 ## 主流查询方案对比 实际开发中,查询 IP 属地主要有三条路线。 ### 方案一:ip2region(纯本地离线,推荐) ```go // Go 中的用法(github.com/lionsoul2014/ip2region/binding/golang) region, err := searcher.SearchByStr(ip) // 返回类似 "中国|福建省|福州市|移动" ``` | 优点 | 缺点 | |------|------| | 免费、无网络依赖、无 QPS 限制 | 段级粒度,个别段可能显示到相邻地区 | | 毫秒级查询,永不因外部服务挂掉 | 数据按月更新,最新分配的段可能短暂缺失 | | 数据文件可随版本更新,不重启 | 只返回省市区+运营商,无经纬度 | **适用**:博客/后台的「登录记录显示归属地」这类展示用途。 ### 方案二:在线 API(ip-api / 高德 / 腾讯位置服务) ```http GET https://ipapi.co/198.51.100.42/json/ ``` | 优点 | 缺点 | |------|------| | 数据最新、可能更精确 | 有频率限制(免费版限 QPS) | | 部分服务还返回经纬度/时区 | 依赖第三方,断网/被墙/限流时拿不到 | | 无需维护数据文件 | 每次查询都要发一次 HTTP 请求 | **适用**:对精度要求高、且能接受外部依赖与限流的场景。 ### 方案三:MaxMind GeoLite2(离线 .mmdb) | 优点 | 缺点 | |------|------| | 全球数据,覆盖广、精度较好 | 需要注册账号下载,商用需授权 | | 标准 `.mmdb` 格式,各语言都有库 | 国内 IP 的省市粒度有时不如 ip2region 细 | | 离线查询 | 数据同样要定期更新 | **适用**:面向全球用户的场景。 ## 局限与诚实提醒 无论用哪种方案,都要清楚 IP 属地的边界: - **段级精度**:网段归属是「绝大多数」准确,个别 IP(大型企业自建段、跨省调度段)可能显示到相邻地区或只到省。 - **运营商级,不是定位**:拿到的是「省|市|运营商」,不是精确街道或基站位置——精确位置需要 GPS 或运营商三角定位,纯 IP 归属做不到。 - **动态 IP**:家宽通常是动态 IP,重拨会变,所以「上次登录在福州,这次在广州」不一定是异常,可能是 IP 变了。 - **别用于安全判定**:用 IP 段做封禁或风控判定风险自负,段级数据不适合当精确依据。 ## 小结 一句话总结: > **IP 属地 = 几十万条「IP 段 → 归属地」映射 + 一次二分查找。** 它查的是网段归属,不是精确位置。 - 想省心、免费、稳定,用 **ip2region** 本地离线查询; - 想要最新最细、能接受外部依赖,用**在线 API**; - 面向全球用户,用 **MaxMind GeoLite2**。 对个人博客「登录记录显示归属地」这种场景,本地离线方案通常是性价比最高的选择。