免费经典语句 API 错误处理:ret_code 非 0 与 showapi_res_error 排查
# 免费经典语句 API 错误处理:ret_code 非 0 与 showapi_res_error 排查
> 元信息:接口 1646-2 · 免费 · 请求方式 POST/GET · 返回 JSON · 适用人群 已接入中高级开发者 · 阅读时间 6 分钟
## 核心要点
- 两层状态码都要判:外层 `showapi_res_code`(系统级)、内层 `ret_code`(业务级),都需为 0。
- 失败时优先读 `showapi_res_error`(系统级)与 `ret_code`(业务级),文档未枚举具体非零错误码,统一按"非 0 即失败"处理。
- 生产环境加超时 + 指数退避重试 + AppKey 失效排查,避免一次抖动拖垮主流程。
## Why:不上错误处理,早晚出事故
免费接口也可能因网络、鉴权、限流返回异常。没有统一的错误分支,前端就会把异常 JSON 当正常数据渲染,用户看到一堆乱码。本文给一套可直接落地的处理骨架。
## What:状态码速览
| 字段 | 位置 | 含义 |
|------|------|------|
| `showapi_res_code` | 系统级 | 0 成功,非 0 看 `showapi_res_error` |
| `showapi_res_error` | 系统级 | 系统级错误文案 |
| `ret_code` | `showapi_res_body` 内 | 0 成功,其余为业务失败(文档未枚举具体码) |
字段细节见 [返回字段全解](https://www.showapi.com/guides/classic-quotes-fields-1646)。
## How:统一处理骨架
**Python:带超时 + 重试**
```python
import requests
import time
def call_quote(tag=None, max_retry=3):
url = "https://route.showapi.com/1646-2"
params = {"appKey": "YOUR_APPKEY"}
data = {"tag": tag} if tag else {}
for attempt in range(max_retry):
try:
js = requests.post(url, params=params, data=data, timeout=10).json()
except requests.RequestException as e:
wait = 2 ** attempt
print(f"网络异常,{wait}s 后重试:{e}")
time.sleep(wait)
continue
if js.get("showapi_res_code") != 0:
raise RuntimeError(f"系统错误:{js.get('showapi_res_error')}")
b = js["showapi_res_body"]
if b.get("ret_code") != 0:
raise RuntimeError(f"业务错误 ret_code={b.get('ret_code')}")
return b
raise RuntimeError("多次重试仍失败")
# 调用方:try/except,失败走缓存或静态兜底
```
**Node.js(fetch)**
```javascript
async function callQuote(tag) {
const url = "https://route.showapi.com/1646-2?appKey=YOUR_APPKEY";
const form = new URLSearchParams();
if (tag) form.append("tag", tag);
const resp = await fetch(url, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: form,
});
const js = await resp.json();
if (js.showapi_res_code !== 0) throw new Error(js.showapi_res_error || "系统错误");
const b = js.showapi_res_body;
if (b.ret_code !== 0) throw new Error(`业务错误 ret_code=${b.ret_code}`);
return b;
}
```
## 返回示例与解析
成功:
```json
{ "showapi_res_code": 0, "showapi_res_body": { "body": "...", "ret_code": 0, "author": "韩愈", "name": "古今贤文" } }
```
失败(示意,具体非零码以接口返回为准):
```json
{ "showapi_res_code": 0, "showapi_res_body": { "ret_code": 1, "body": "", "author": "", "name": "" } }
```
> 注意:上述 `ret_code: 1` 仅为示意"非 0 即失败"的结构,**文档未给出具体非零码表**,请以接口实际返回为准,不要硬编码"1 代表某特定错误"。
## 进阶 / 边界
- **不要编造错误码映射**:文档只给二态,代码中用 `!= 0` 判断,不要写 `if ret_code == -2` 之类未文档化的分支。
- **AppKey 失效**:返回系统级异常时,先排查 AppKey 是否过期/写错/被重置。
- **限流**:文档未给明确 QPS;高频调用建议先缓存(见 [缓存策略](https://www.showapi.com/guides/classic-quotes-cache-1646))再展示。
## FAQ
**Q:ret_code 非 0 时 body 是空吗?**
文档未约定非 0 时 body 必空,应以实际返回为准;判成功只看 `ret_code == 0`,不要假设失败必带空 body。
**Q:showapi_res_error 为空但 ret_code 非 0 怎么办?**
按"业务失败"处理,记录 `ret_code` 值用于排查;不臆测具体含义,必要时联系官方(service@showapi.com)。
**Q:重试几次合适?**
低频场景 2~3 次指数退避(如 1s/2s/4s)足够;避免无退避的死循环。
**Q:AppKey 报错怎么快速定位?**
先单独跑一次官方调用帮助里的 cURL([帮助中心](https://www.showapi.com/helpcenter/view#/3960/1)),确认 AppKey 与参数无误。
**Q:前端怎么不暴露接口异常?**
后端/客户端统一捕获异常,展示缓存句或静态金句,绝不直接渲染原始错误 JSON。
## 相关能力 / 下一步阅读
- [免费经典语句 API 返回字段全解](https://www.showapi.com/guides/classic-quotes-fields-1646) — 字段与状态码
- [免费接口也要省:经典语句客户端缓存策略](https://www.showapi.com/guides/classic-quotes-cache-1646) — 失败回落
- [5 分钟接入免费经典语句 API](https://www.showapi.com/guides/classic-quotes-quickstart-1646) — 基础调用
- **本系列共 11 篇**:查看[免费经典语句 API 开发指南总目录](https://www.showapi.com/guides/classic-quotes-guides-1646)