技术博客
手机归属地查询错误码排查:-2 非11位 / -3 非数字 / -4 格式 / -5-6 找不到

手机归属地查询错误码排查:-2 非11位 / -3 非数字 / -4 格式 / -5-6 找不到

作者: 万维易源
2026-08-27
手机归属地查询错误码ret_code格式校验
# 手机归属地查询错误码排查:-2 非11位 / -3 非数字 / -4 格式 / -5-6 找不到 > **接口**:手机归属地查询 `6-1` | **是否免费**:是(注册默认可免费调用,有使用档次限制)| **请求方式**:POST / GET | **返回格式**:JSON | **适用人群**:前后端开发、表单/风控接入者 | **阅读时间**:约 6 分钟 ## TL;DR - 4 类错误码都来自 `showapi_res_body.ret_code`:**-2 非11位 / -3 非数字 / -4 格式错 / -5-6 找不到归属地**,全部 < 0。 - **失败时(ret_code != 0)不扣点数**——所以不怕试,但更该在客户端先做格式校验,省下调用量。 - 一条正则 `^1[3-9]\d{9}$` 就能拦掉绝大多数无效请求,把错误挡在调用之前。 ## Why:为什么要把错误码讲透? 接入任何外部接口,第一道坎从来不是"怎么成功",而是"失败了怎么办"。手机归属地查询的错误码集中在 `showapi_res_body.ret_code` 上:**成功是 0,失败全是负数**。负数又分两类—— - 一类是**你传错了**(号码不是 11 位、含非数字字符、格式不对):`-2 / -3 / -4`; - 一类是**接口查不到**(号段库里没有这个归属地):`-5 / -6`。 区别在哪?前者是**客户端能提前校验拦掉的**,后者是**数据本身缺失**。把两类分开,你就能决定:前者在提交前就拦,后者按"未知"分支处理。而且最关键的一点——**失败不扣点数**,这意味着你可以放心做格式校验、甚至批量试,但更聪明的做法是"先校验、再调用",把免费档位的额度留给真正有效的查询。 ## What:前置条件与错误码速览 | 项目 | 内容 | |------|------| | 接口名称 | 手机归属地查询 | | 接入点 | `6-1`(仅 1 个接入点,同步请求-响应) | | 接口地址 | `https://route.showapi.com/6-1?appKey={your_appKey}` | | 必填参数 | `num`(手机号,字符串) | | 成功标志 | `showapi_res_body.ret_code == 0` | | 失败标志 | `ret_code < 0`(不扣点数) | | 计费 | 免费服务;**失败不扣点数** | ### 错误码对照表 | ret_code | 含义 | 类别 | 客户端能否提前拦 | 建议处理 | |----------|------|------|------------------|----------| | `0` | 成功 | — | — | 读取 prov/city/type 等业务字段 | | `-2` | 不是 11 位 | 格式(输入) | 能(长度校验) | 提示"请输入 11 位手机号" | | `-3` | 含非数字字符 | 格式(输入) | 能(纯数字校验) | 提示"手机号只能含数字" | | `-4` | 格式错误 | 格式(输入) | 能(正则校验) | 统一提示格式不符 | | `-5` | 找不到归属地 | 数据缺失 | 否 | 标记"未知",走未知分支 | | `-6` | 找不到归属地 | 数据缺失 | 否 | 标记"未知",走未知分支 | > 注意:`ret_code` 是**业务状态码**,位于 `showapi_res_body` 内;最外层的 `showapi_res_code` 是系统级状态码(成功为 0)。两者都要看:**外层决定请求是否送达,内层决定业务是否成功**。本文关注内层的 `ret_code`。 ## How:客户端前置校验 + 调用与判断 ### 步骤 1 · 客户端先做格式校验(强烈建议) 在把号码发给接口之前,用一行正则拦掉 `-2 / -3 / -4` 三类错误,直接省掉一次调用: ```python import re PHONE_RE = re.compile(r"^1[3-9]\d{9}$") # 11 位、纯数字、1 开头第 2 位 3-9 def is_valid_phone(num: str) -> bool: return bool(PHONE_RE.match(num or "")) # 用法 raw = input("手机号:") if not is_valid_phone(raw): print("格式不合法(应为 11 位纯数字),已拦截,未发起调用") else: print("格式通过,准备调用接口") ``` 正则说明:`^1` 限定 1 开头,`[3-9]` 覆盖当前号段第二位范围,`\d{9}` 接后续 9 位,正好 11 位。它能在客户端拦截**非 11 位(-2)、含非数字字符(-3)、格式错误(-4)**三类问题。 ### 步骤 2 · 发起调用并读取 ret_code ```python import requests API_URL = "https://route.showapi.com/6-1" APP_KEY = "YOUR_APPKEY" PHONE = "18908711111" # 先校验,再调用 if not is_valid_phone(PHONE): raise ValueError("手机号格式不合法,未发起调用") resp = requests.get( API_URL, params={"appKey": APP_KEY, "num": PHONE}, timeout=10, ) data = resp.json() body = data.get("showapi_res_body", {}) rc = body.get("ret_code") if rc == 0: print("归属地:", body.get("prov"), body.get("city"), "运营商:", body.get("name")) elif rc in (-5, -6): # 数据缺失:查不到归属地 print("查不到归属地(ret_code=%s),按未知处理(失败不扣点数)" % rc) else: # -2 / -3 / -4 等格式类错误 print("格式/输入错误(ret_code=%s),应已在客户端拦截(失败不扣点数)" % rc) ``` ### 步骤 3 · 排查路径(出问题照这张图走) 1. **看外层 `showapi_res_code`**:非 0 说明请求没到接口(网络/鉴权/appKey 问题),先查 `showapi_res_error` 文案。 2. **看内层 `ret_code`**: - `-2 / -3 / -4` → 检查传入 `num` 是否为合法 11 位纯数字,补上步骤 1 的正则。 - `-5 / -6` → 号段库暂无该归属地,属数据缺失,按"未知"分支处理,不要重试同号。 3. **确认不扣点数**:无论哪类失败,`ret_code != 0` 都不消耗额度,可安心校验与核对。 ## 返回示例与解析 ```json { "showapi_res_code": 0, "showapi_res_error": "", "showapi_res_id": "ce135f6739294c63be0c021b76b6fbff", "showapi_res_body": { "num": 1890871, "prov": "云南", "ret_code": 0, "areaCode": "0871", "name": "电信", "cityCode": "530100", "postCode": "650000", "provCode": "530000", "type": 2, "city": "昆明" } } ``` | 字段 | 类型 | 含义 | 本例值 | |------|------|------|--------| | `showapi_res_code` | Number | 系统级状态码,0 成功 | `0` | | `showapi_res_error` | String | 系统级错误信息 | `""` | | `ret_code` | Number | 业务状态码(0 成功,<0 失败) | `0` | | `prov` / `city` / `name` | String | 省 / 市 / 运营商名 | 云南 / 昆明 / 电信 | > 字段完整含义见 [《手机归属地返回字段全解:prov/city/type/postCode 一文读懂》](https://www.showapi.com/guides/phone-attribution-response-fields-6)。失败时只看 `ret_code`,其余业务字段不可信。 ## 进阶 / 边界 - **失败不扣点数**是核心福利:`-2/-3/-4/-5/-6` 全部不消耗额度,但更优解是客户端先校验,把免费档位留给有效查询。 - **正则不是万能**:`^1[3-9]\d{9}$` 能拦格式,拦不掉 `-5/-6`(号段库缺失),后者需业务侧按"未知"兜底。 - **别重试 -5/-6**:数据缺失不是偶发,对同一号码重试通常仍失败,且浪费调用量。 - **免费档位限制**:免费调用有使用档次上限,配合客户端校验 + 本地缓存(按号段前 7 位)能显著降低调用次数。 ## FAQ **Q1:ret_code 和 showapi_res_code 有什么区别?** `showapi_res_code` 是系统级(请求是否送达/鉴权是否通过),`ret_code` 是业务级(查询是否成功)。两者为 0 才是真成功;`ret_code < 0` 即本文讲的 4 类错误。 **Q2:失败真的不扣点数吗?** 不扣。文档明确"失败时不扣点数",`ret_code != 0` 即失败且不扣费,可放心做格式校验与核对。 **Q3:正则能拦掉所有错误吗?** 能拦 `-2/-3/-4`(格式类),但拦不掉 `-5/-6`(号段库缺失)。后者需业务侧按"未知/查不到"分支处理,不要靠正则。 **Q4:返回的 num 是完整手机号吗?** 不是。`num` 返回的是**号段(前 7 位)**,如 `1890871`,不是完整号码,做校验时请用你自己的原始输入,别拿返回去回比。 **Q5:-5 和 -6 需要分别处理吗?** 两者都是"找不到归属地",业务上可统一按"未知"分支处理,无需区分。文档未给二者更细的差异定义。 **Q6:客户端校验后还需要判断 ret_code 吗?** 需要。校验只拦格式类错误,数据缺失(-5/-6)和偶发情况仍会出现,调用后必须读 `ret_code` 再决定分支。 ## 相关能力 / 下一步阅读 - [《手机归属地查询:从注册到第一条返回》](https://www.showapi.com/guides/phone-attribution-quickstart-6) —— 还没跑通接口先看这篇 - [《手机归属地返回字段全解:prov/city/type/postCode 一文读懂》](https://www.showapi.com/guides/phone-attribution-response-fields-6) —— 字段类型与失败时的可信度 - [《注册/表单防错:用手机号归属地做实时校验与运营商识别》](https://www.showapi.com/guides/phone-attribution-form-validation-6) —— 把正则校验落到表单实时校验 - **本系列共 12 篇**:查看[手机归属地查询 · 官方指南总目录](https://www.showapi.com/guides/phone-attribution-guides-6)