歇后语查询错误处理:ret_code / showapi_res_code 与重试指南
# 歇后语查询错误处理:ret_code / showapi_res_code 与重试指南
- **接口/接入点**:歇后语查询 · 1635-1
- **是否免费**:是
- **请求方式**:POST / GET
- **返回格式**:JSON
- **适用人群**:中高级开发者、需要稳定集成的工程师
- **阅读时间**:约 6 分钟
## 核心要点
- 有两层状态码:`showapi_res_code`(系统级,int)和 `showapi_res_body.ret_code`(业务级,String `"0"` 成功)。
- 文档**未给出失败码枚举**,只说明 `ret_code` "0 为成功,其他为失败",不要臆造具体失败码。
- 官方超时约 15s;生产用超时 + 指数退避重试,别裸奔。
## Why:为什么要单独讲错误处理
免费接口也会偶发网络抖动、超时、限频。两层状态码语义不同,只判 HTTP 200 不够;把判错与重试写对,产品才不会"静默失败"。
## What:两层状态码
| 字段 | 位置 | 类型 | 说明 |
|------|------|------|------|
| `showapi_res_code` | 系统包裹层 | int | 系统级状态,0 通常正常 |
| `showapi_res_error` | 系统包裹层 | String | 系统级错误描述 |
| `ret_code` | `showapi_res_body` | String | `"0"` 业务成功,其他失败 |
| `remark` | `showapi_res_body` | String | 业务提示信息 |
> 文档仅说明 `ret_code` 二元(0/非0),**无完整失败码枚举**,代码里只判 `!= "0"` 并读取 `remark`,不写死具体失败码。
## How:健壮调用模板
```python
import requests, time
def call_xiehouyu(num="3", max_retry=3):
url = "https://route.showapi.com/1635-1"
for attempt in range(max_retry):
try:
r = requests.post(url, params={"appKey": "YOUR_APPKEY"},
data={"num": num}, timeout=15)
r.raise_for_status()
res = r.json()
if res.get("showapi_res_code") != 0:
raise RuntimeError("系统错误: " + str(res.get("showapi_res_error")))
body = res["showapi_res_body"]
if body.get("ret_code") != "0":
# 业务失败:读 remark,按可重试/不可重试处理
raise RuntimeError("业务失败: " + str(body.get("remark")))
return body["contentlist"]
except requests.exceptions.Timeout:
wait = 2 ** attempt
time.sleep(wait) # 指数退避
except requests.exceptions.RequestException as e:
time.sleep(2 ** attempt)
raise RuntimeError("重试后仍失败")
```
**cURL**(注意加 `--max-time`)
```bash
curl --max-time 15 -X POST "https://route.showapi.com/1635-1?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" -d "num=3"
```
**Node.js**
```javascript
async function callXiehouyu(num = "3") {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), 15000);
try {
const r = await fetch("https://route.showapi.com/1635-1?appKey=YOUR_APPKEY", {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ num }),
signal: ctrl.signal,
});
const res = await r.json();
if (res.showapi_res_code !== 0) throw new Error(res.showapi_res_error);
const body = res.showapi_res_body;
if (body.ret_code !== "0") throw new Error(body.remark);
return body.contentlist;
} finally { clearTimeout(t); }
}
```
## 返回示例与解析
```json
{
"showapi_res_code": 0,
"showapi_res_error": "",
"showapi_res_body": { "ret_code": "0", "remark": "查询成功", "contentlist": [] }
}
```
失败示例(结构示意,具体 remark 以接口返回为准):
```json
{ "showapi_res_code": 0, "showapi_res_body": { "ret_code": "1", "remark": "..." } }
```
## 进阶 / 边界
- **不要编造失败码**:文档只给 0/非0,代码统一判 `!= "0"` + 读 `remark`。
- **超时退避**:官方 15s 超时,重试用指数退避,避免雪崩。
- **降级**:接口失败时返回本地兜底语料,页面不空。
## FAQ
**Q:ret_code 非 0 时有哪些具体错误码?**
A:文档仅说明 0 成功、其他失败,未给完整枚举;代码统一判非 0 并读取 `remark` 提示,不写死具体码。
**Q:HTTP 200 就算成功吗?**
A:不算,还要看 `showapi_res_code`(系统)和 `ret_code`(业务)两层都为成功。
**Q:超时设多少?**
A:官方读写超时均 15s,客户端建议设 15s 并加重试退避。
**Q:限频怎么处理?**
A:免费接口有档次限制,遇失败可降低频率/走本地缓存;具体档位以官方说明为准。
**Q:showapi_res_id 有什么用?**
A:请求唯一标识,反馈异常给官方时附带它便于定位。
## 相关能力 / 下一步阅读
- [歇后语查询返回字段全解:contentlist / ret_code / 分页字段一文读懂](https://www.showapi.com/guides/xiehouyu-response-fields-1635)
- [免费接口也要稳:歇后语查询本地缓存与去重策略](https://www.showapi.com/guides/xiehouyu-cache-dedup-1635)
- **本系列共 13 篇**:查看[歇后语查询指南总目录](https://www.showapi.com/guides/xiehouyu-guides-1635)