IP 归属地查询是访问统计、地域标注、风控识别等场景的基础能力。随着网络协议从 IPv4 向 IPv6 演进,"查一个 IP 能拿到哪些归属信息"不再是一个单一答案——IPv4 与 IPv6 在地址长度、地址结构、可分配地址空间、常见用途上差异很大,对应的归属地接口在请求方式、精度粒度、返回字段上也各不相同。本文围绕两个高精度 IP 定位接口展开:一个是面向 IPv4 的高精度归属地查询,一个是面向 IPv6 的高精度定位查询。本文会逐项拆解两者的能力边界、参数设计、返回结构与工程实践,帮助你在"该用哪个接口"以及"返回结果怎么用"上做出判断。

一、技术简介
两个接口都基于最新的 IP 地址数据库,把 IP 地址转换为地理位置信息,但服务对象不同:
- IPv4 高精度归属地查询:针对 IPv4 地址,覆盖国内外,定位精度可达县区级,返回国家、省份、城市、县区、运营商、经纬度、行政区划编码等多维度字段。
- IPv6 高精度定位查询:针对 IPv6 地址,基于多源权威数据源融合构建。国内 IPv6 地址大部分可定位至市级(含部分重点区县),国外 IPv6 地址可稳定解析至国家/地区级。
两者的共同点是通过统一网关封装返回,业务数据放在同一个 showapi_res_body 对象里;不同点在于协议族、精度粒度和返回字段集。下面从能力、参数、返回、示例、限制、边界、错误码、FAQ 逐项展开。
二、能力概览
| 维度 | IPv4 高精度归属地查询 | IPv6 高精度定位查询 |
|---|---|---|
| 协议族 | IPv4 | IPv6 |
| 请求方式 | GET | GET |
| 定位精度 | 国内外,县区级 | 国内市级(部分区县),国外国家级 |
| 典型字段 | 国家/省/市/县区/运营商/经纬度/行政区划码 | 洲/国家/国家简写/省/市/经度/纬度/行政区码/运营商/时区/邮编/城市代码 |
| 地址规模 | 32 位,约 43 亿个地址 | 128 位,地址空间极大 |
| 主要用途 | 存量业务、传统终端归属标注 | 新建终端、移动网络、物联网归属标注 |
| 数据更新 | 不定期更新维护 | 动态更新 IP 库 + 智能解析算法 |
这张表回答的核心问题是:同一个"IP 归属地"需求,按 IP 版本要分别选接口。一个请求里既有 IPv4 又有 IPv6 终端时,需要按地址版本分流到两个接口分别查询。

三、适用场景
- 访问来源地域标注:把用户 IP 落到"省-市-运营商",用于内容分发、地域统计。IPv4 场景精度到县区,IPv6 场景到市级(国外到国家)。
- 业务风控:识别异常地域访问。IPv6 地址在移动网络、物联网终端占比逐年上升,纯 IPv4 的风控规则容易漏掉这部分流量。
- 运维排障:定位报障用户的大致地理位置。
- 多终端并存:同一业务同时服务 IPv4/IPv6 用户时,按版本分流,避免"IPv6 地址塞进 IPv4 接口"导致解析失败。
四、接入流程(含参数设计)
两个接口的接入流程一致,差别只在待查询的 IP 是 IPv4 还是 IPv6。
- 获取调用凭证:在控制台获取 AppCode,调用时在请求头里携带鉴权信息。
- 判定 IP 版本:对入参 IP 做版本判定(
:出现即 IPv6,.分隔四段即 IPv4),决定调用哪个接口。 - 构造 GET 请求:把 IP 作为
ip查询参数拼到 Query。 - 发送请求并解析:读取外层信封与
showapi_res_body两层状态。
IPv4 接口请求参数(Query)
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| ip | string | 是 | 待查询的 IPv4 地址 | 223.5.5.5 |
IPv6 接口请求参数(Query)
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|---|---|---|---|---|
| ip | string | 是 | 待查询的 IPv6 地址 | 2408:874d:a00:1::1:b |
鉴权统一走请求头:
Authorization: APPCODE <appcode>。IPv6 地址里含有:,拼 URL 时建议做 URL 编码,避免被解析成多个参数。

五、调用示例与返回结构
5.1 IPv4 接口:请求示例
GET /ip?ip=223.5.5.5
Authorization: APPCODE <appcode>
成功返回样例(字段经中性化处理,实际以接口返回为准):
{
"showapi_res_code": 0,
"showapi_res_error": "",
"showapi_res_id": "ce135f6739294c63be0c021b76b6fbff",
"showapi_res_body": {
"ret_code": 0,
"country": "中国",
"region": "广东",
"city": "东莞",
"county": "南城",
"isp": "电信",
"area": "华南",
"lnt": "113.760234",
"lat": "23.048884",
"city_code": "441900"
}
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| ret_code | int | 业务返回码,0 表示成功 |
| country | string | 国家/地区 |
| region | string | 省份 |
| city | string | 城市 |
| county | string | 县区,部分地址可能为空 |
| isp | string | 运营商 |
| area | string | 片区 |
| lnt / lat | string | 经度 / 纬度 |
| city_code | string | 行政区划编码 |
5.2 IPv6 接口:请求示例
GET /ipv6/getip?ip=2408%3A874d%3Aa00%3A1%3A%3A1%3Ab
Authorization: APPCODE <appcode>
成功返回样例:
{
"showapi_res_error": "",
"showapi_fee_num": 1,
"showapi_res_code": 0,
"showapi_res_id": "66160b2ffb638c08b87eca95",
"showapi_res_body": {
"ret_code": 0,
"continent": "亚洲",
"country": "中国",
"country_code": "CN",
"province": "广东",
"city": "广州",
"longitude": "113.280",
"latitude": "23.1251",
"area_code": "440100",
"isp": "移动",
"time_zone": "Asia/Shanghai",
"zip_code": "510000",
"city_code": "020",
"county": ""
}
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| ret_code | int | 业务返回码,0 表示成功 |
| continent | string | 所属七大洲 |
| country / country_code | string | 国家 / 国家英文简写 |
| province / city | string | 省份 / 城市 |
| longitude / latitude | string | 经度 / 纬度 |
| area_code | string | 行政区划编码 |
| isp | string | 运营商 |
| time_zone | string | 时区 |
| zip_code / city_code | string | 邮编 / 城市代码 |
| county | string | 区县,部分地址可能为空 |

5.3 多语言调用示例(以 IPv6 接口为例)
Python:
import requests
url = "https://<调用地址>/ipv6/getip"
headers = {
"Authorization": "APPCODE <appcode>"}
params = {
"ip": "2408:874d:a00:1::1:b"}
r = requests.get(url, params=params, headers=headers, timeout=10)
body = r.json().get("showapi_res_body")
if body and body.get("ret_code") == 0:
print(body.get("country"), body.get("province"), body.get("city"), body.get("isp"))
else:
print("查询失败")
Java:
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
public class IpV6Query {
public static void main(String[] args) throws Exception {
URL u = new URL("https://<调用地址>/ipv6/getip?ip=2408%3A874d%3Aa00%3A1%3A%3A1%3Ab");
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestProperty("Authorization", "APPCODE <appcode>");
Scanner s = new Scanner(c.getInputStream()).useDelimiter("\\A");
String json = s.hasNext() ? s.next() : "";
System.out.println(json); // 解析 showapi_res_body
}
}
cURL:
curl -i -k --get 'https://<调用地址>/ipv6/getip?ip=2408%3A874d%3Aa00%3A1%3A%3A1%3Ab' \
-H 'Authorization: APPCODE <appcode>'
调用地址以控制台实际下发为准,本文示例用
<调用地址>占位,避免硬编码具体域名。
六、在线调试实录
以一个"同一业务同时收到 IPv4 与 IPv6 访问"的场景做参数设计:
- 任务:对用户上报的来源 IP 做归属地标注并落库。
- 输入:
116.232.33.245(IPv4)与2408:874d:a00:1::1:b(IPv6)。 - 步骤轨迹:版本判定 → 按版本分流 → 构造 GET 携带 AppCode → 网关查询 → 封装
showapi_res_body→ 返回。 - 结果解读:IPv4 命中到"省-市-县区-运营商",IPv6 命中到"省-市-运营商"(国外则到国家)。
- 耗时:同步调用,单次请求即返回结果,整体响应较快。

调试时务必同时打印外层
showapi_res_code与内层showapi_res_body.ret_code,两层都判(见第九节)。
七、调用限制与规范
- 鉴权:统一使用
Authorization: APPCODE <appcode>;密钥需妥善保管,不要写进前端代码或公开仓库。 - IPv6 编码:IPv6 地址含
:,拼 Query 必须做 URL 编码,否则会被网关解析成多个参数。 - 两层状态码:外层
showapi_res_code(网关级)与内层showapi_res_body.ret_code(业务级)都要判,只判外层会漏掉业务失败。 - 扣减规则:仅当 HTTP 响应状态码为 200 时才扣减调用次数,非 200 不扣费。
- 重试与幂等:归属地查询是幂等只读操作,可对瞬时网络错误做有限次重试;不要对同一 IP 做无意义的高频轮询,命中结果可缓存复用。
- 合规与数据安全:IP 归属地仅作为辅助定位信息,不得作为唯一的风控判定依据;日志落库时注意对敏感信息脱敏,遵守相关数据合规要求。

八、能力边界与免责声明
- 支持:国内外 IPv4 地址到县区级;国内 IPv6 到市级(部分区县),国外 IPv6 到国家/地区级。
- 不支持 / 边界:
- 私有/保留地址段(如
10.x、172.16-31.x、192.168.x,以及 IPv6 的fc::/7、fe80::/10)一般无公网归属,接口不保证返回有效地理位置。 - IPv4 接口不解析 IPv6 地址,IPv6 接口不解析 IPv4 地址,跨版本使用会失败。
- 经纬度、行政区码等字段在部分边缘地址下可能为空或不完整,需做兜底。
- 私有/保留地址段(如
- 免责声明:IP 归属地数据基于 IP 地址库,仅作辅助定位参考,不保证 100% 精确到门牌;据此做出的业务决策需结合其他信号综合判断。数据仅供参考。
九、错误码排查
网关型接口需要同时看两层状态:外层 showapi_res_code 与业务 showapi_res_body.ret_code。
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
外层 showapi_res_code 非 0 |
网关级错误(鉴权、限流、参数) | 看 showapi_res_error 定位 |
| 鉴权 401 / AppCode 无效 | AppCode 未授权、拼错或未带请求头 | 核对 AppCode 与请求头格式 |
内层 ret_code 非 0 |
业务级失败(该 IP 无数据 / 参数非法) | 对无公网归属的 IP 做兜底,标注"未知" |
| IPv6 解析为空 | 地址未做 URL 编码,被拆成多参数 | 对 : 做编码后重试 |
| 429 限流 | 触发流控 | 降低频率 + 结果缓存 + 指数退避重试 |
| 403 订购类错误 | 订购关系过期/配额耗尽 | 续费或重新订购后重试 |
排查顺序建议:先外层后内层;再按"参数 → 鉴权 → 限流 → 订购"逐项核对。
十、技术 FAQ
Q1:IPv4 和 IPv6 接口能互相替代吗?
不能。两个接口的解析库与地址结构不同,IPv4 接口不解析 IPv6 地址,反之亦然。需要按 IP 版本分别调用。
Q2:精度差异会不会影响风控?
会。IPv4 可到县区,IPv6 国内到市级、国外到国家。做地域风控时,IPv6 侧的地域判定粒度天然比 IPv4 粗,阈值与规则要按协议版本分别配置。
Q3:IPv6 地址为什么一定要 URL 编码?
IPv6 地址里的 : 是 URL 里 Query 分隔与键值分隔的敏感字符。直接拼接会被网关解析成多个参数,导致校验失败,必须对 : 编码(%3A)。
Q4:两层状态码为什么都要判?showapi_res_code 是网关级(鉴权、限流、参数是否被网关接受),showapi_res_body.ret_code 是业务级(这条 IP 有没有查出来)。只判外层会漏掉"网关成功但业务无数据"的情况。
Q5:私有地址段能查吗?10.x、192.168.x、IPv6 私有/链路本地段一般没有公网归属,接口不保证返回有效地理位置,建议直接按"内网/未知"处理。
Q6:结果可以缓存吗?
可以。归属地是低频变化的只读数据,相同 IP 的结果可做缓存复用,降低调用量,也更利于幂等与限流控制。
十一、内容小结
- 选型一句话:先判 IP 版本,IPv4 走高精度归属地接口(县区级),IPv6 走高精度定位接口(国内市级 / 国外国家级)。
- 参数一致、返回不同:两者请求方式都是 GET +
ip参数,但返回字段集与精度粒度不同,落库与展示逻辑要按版本区分。 - 工程要点:IPv6 必做 URL 编码;两层状态码都判;私有地址段兜底;结果做缓存,控制调用频率。
- 合规边界:归属地仅作辅助定位,不作为唯一风控依据;敏感信息落库注意脱敏。
把 IPv4 与 IPv6 当两套独立能力来接入、按版本分流处理,是这两个高精度 IP 定位接口落地时最该记住的一点。