绕口令与谜语查询:错误处理与 ret_code 排查(0 为成功、其余为失败)
错误处理ret_codeshowapi_res_code超时限流 # 绕口令与谜语查询:错误处理与 ret_code 排查(0 为成功、其余为失败)
**接口**:绕口令与谜语查询(apiCode=1623)· 接入点 1623-1 / 1623-2|**是否免费**:免费(含使用档次限制)|**返回格式**:JSON|**适用人群**:已接入或准备上生产的开发者|**阅读时间**:约 6 分钟
## 核心要点
- 返回有**两层**状态码:系统级 `showapi_res_code`(网关层)与业务级 `showapi_res_body.ret_code`(接口层),失败排查两个都要看。
- `ret_code` 只有两个语义:`"0"` 成功,非 `"0"` 失败。**文档未给出非 0 的具体枚举值**,失败原因统一读 `showapi_res_error` 文案,不要臆测具体数字。
- 常见失败:AppKey 无效/未开通、免费档位受限、网络超时(绕口令 5s / 谜语 15s)、关键词无匹配(此时 `ret_code` 可能仍为 `"0"` 但 `contentlist` 为空)。
## Why:分清两层码,少走弯路
新手常把 `showapi_res_code` 和 `ret_code` 混为一谈,或一见非 0 就去猜「是不是参数错」。其实失败信息就在 `showapi_res_error` 里。这篇教你稳定地判断成功/失败与兜底。
## What:两层状态码对照
| 层级 | 字段 | 位置 | 说明 |
|------|------|------|------|
| 系统级 | `showapi_res_code` | 信封顶层 | API 网关层状态码(整数) |
| 系统级 | `showapi_res_error` | 信封顶层 | 网关层错误信息,失败时非空 |
| 业务级 | `ret_code` | `showapi_res_body` 内 | 接口业务状态码:`"0"` 成功,其余失败 |
| 业务级 | (失败详情) | `showapi_res_error` | 非 0 时参考同一 `showapi_res_error` 文案 |
## How:健壮的错误处理(Python)
```python
import requests
APP_KEY = "YOUR_APPKEY"
URL = "https://route.showapi.com/1623-1" # 谜语改用 1623-2,timeout 15
def safe_query(keyword: str, page: int = 1):
try:
resp = requests.post(
URL,
params={"appKey": APP_KEY},
data={"title": keyword, "page": str(page)},
timeout=5,
)
resp.raise_for_status() # HTTP 层异常(如 5xx)
data = resp.json()
except requests.RequestException as e:
# 网络/超时层:绕口令 5s、谜语 15s 超时会落在这里
return None, f"网络请求失败:{e}"
# 系统级
if data.get("showapi_res_code") != 0:
return None, f"系统错误 {data.get('showapi_res_code')}:{data.get('showapi_res_error')}"
# 业务级
body = data["showapi_res_body"]
if body.get("ret_code") != "0":
return None, f"业务失败:{data.get('showapi_res_error')}"
# 空结果不是错误,但要单独提示
if not body.get("contentlist"):
return body, "查询成功,但无匹配结果(contentlist 为空)"
return body, None
```
**Node.js(fetch)**
```javascript
const APP_KEY = "YOUR_APPKEY";
async function safeQuery(keyword, page = 1) {
let data;
try {
const url = `https://route.showapi.com/1623-1?appKey=${APP_KEY}`;
const body = new URLSearchParams({ title: keyword, page: String(page) });
const resp = await fetch(url, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body,
signal: AbortSignal.timeout(5000),
});
data = await resp.json();
} catch (e) {
return { error: `网络请求失败:${e.message}` };
}
if (data.showapi_res_code !== 0)
return { error: `系统错误 ${data.showapi_res_code}:${data.showapi_res_error}` };
const resBody = data.showapi_res_body;
if (resBody.ret_code !== "0")
return { error: `业务失败:${data.showapi_res_error}` };
if (!resBody.contentlist.length)
return { body: resBody, notice: "查询成功,但无匹配结果" };
return { body: resBody };
}
```
## 返回示例与解析
失败时典型形态(示意,文案以实际返回为准):
```json
{
"showapi_res_code": 0,
"showapi_res_error": "",
"showapi_res_body": {
"ret_code": "0",
"contentlist": []
}
}
```
> 注意:上例 `ret_code` 为 `"0"` 但 `contentlist` 为空——属于「成功但无匹配」,应与真正的失败区分。
## 进阶 / 边界
- **不要臆造错误码表**:文档只给「0 成功、其余失败」,非 0 的具体含义以 `showapi_res_error` 文案为准,本系列文章均不编造具体数字。
- **超时分层**:绕口令 5s、谜语 15s(来自 OpenAPI `x-read-timeout`),客户端超时建议与之对齐或略大。
- **档位受限**:免费接口超量会失败,错误文案通常与档位相关,配合[本地缓存策略](https://www.showapi.com/guides/tongue-riddle-cache-tier-1623) 缓解。
- 前端侧防刷见[前端限流与防滥用](https://www.showapi.com/guides/tongue-riddle-frontend-throttle-1623)。
## FAQ
**Q1:ret_code 非 0 时去哪查错误含义?**
A:读 `showapi_res_error` 文案;同时看系统级 `showapi_res_code`/`showapi_res_error`。文档未提供非 0 枚举,不臆测。
**Q2:contentlist 为空算失败吗?**
A:不一定。`ret_code` 为 `"0"` 但无匹配时 `contentlist` 为空数组,属「成功无结果」,按业务逻辑提示「未找到」即可。
**Q3:超时算哪种失败?**
A:网络/超时层,落到 HTTP 客户端异常(如上面 `requests.RequestException`),与业务 `ret_code` 无关;按接入点设 5s/15s。
**Q4:AppKey 错了会怎样?**
A:通常表现为系统级或业务级失败,具体文案以返回为准;确认 AppKey 来自[控制台](https://www.showapi.com/console#/myApp) 且接口已开通。
**Q5:要不要重试?**
A:网络超时/5xx 可指数退避重试;业务级「参数/档位」类失败重试无意义,应先修正再调。
## 下一步阅读
- [绕口令与谜语查询:返回字段与 ret_code 全解](https://www.showapi.com/guides/tongue-riddle-response-fields-1623)
- [绕口令与谜语查询:免费档位下的调用纪律与本地缓存策略](https://www.showapi.com/guides/tongue-riddle-cache-tier-1623)
- [绕口令与谜语查询:前端限流与防滥用实践](https://www.showapi.com/guides/tongue-riddle-frontend-throttle-1623)
- **本系列共 12 篇**:查看[绕口令与谜语查询指南总目录](https://www.showapi.com/guides/tongue-riddle-guides-1623)