# 毒鸡汤接口 5 秒超时下,如何做重试与容错?
> 接口/接入点:毒鸡汤生成(apiCode 2784,接入点 1) · 是否免费:免费 · 请求方式:POST/GET · 返回格式:JSON · 适用人群:中高级开发者、架构师 · 阅读时间:约 6 分钟
## 核心要点
- 官方超时 **read/connect 均为 5 秒**,代码里必须显式设置超时,否则可能无限挂起。
- 区分两类失败:**网络层超时/异常**(可重试)与**业务层 `ret_code=-1`**(看 `remark`,多数不应盲目重试)。
- 重试用**指数退避 + 抖动**,并设置上限与兜底文案,避免雪崩与无意义重试。
## Why:为什么 5 秒超时值得专门处理
免费接口有时会有抖动,5 秒是官方给的硬上限。如果不设超时,你的调用线程可能一直等;如果无脑重试,一次抖动会被放大成多次无效请求,既浪费免费额度又拖垮自身服务。正确做法:超时即快速失败 + 有限重试 + 兜底。
## What:接口速览
| 项目 | 说明 |
|------|------|
| 接口地址 | `https://route.showapi.com/2784-1` |
| 超时 | 官方 read/connect 各 5 秒 |
| 失败表现 | 网络超时(请求异常)/ 业务 `ret_code=-1` + `remark` |
## How:生产级重试(Python)
```python
import requests, time, random
API_URL = "https://route.showapi.com/2784-1"
APP_KEY = "YOUR_APPKEY"
MAX_RETRY = 3
BASE_DELAY = 0.5 # 退避基数(秒)
def get_poison_soup():
last_err = "未知错误"
for attempt in range(MAX_RETRY):
try:
resp = requests.post(
API_URL,
params={"appKey": APP_KEY},
headers={"content-type": "application/x-www-form-urlencoded"},
timeout=5, # 对齐官方 5 秒
)
resp.raise_for_status()
body = resp.json().get("showapi_res_body", {})
if body.get("ret_code") == 0:
return body.get("emposion", "")
# 业务失败:读 remark,不再盲目重试
last_err = body.get("remark", "业务返回失败")
break
except requests.exceptions.Timeout:
last_err = "请求超时"
except requests.exceptions.RequestException as e:
last_err = f"请求异常: {e}"
# 指数退避 + 抖动(最后一次不 sleep)
if attempt < MAX_RETRY - 1:
time.sleep(BASE_DELAY * (2 ** attempt) + random.uniform(0, 0.3))
return f"毒鸡汤暂时煮糊了({last_err}),稍后再来一句~" # 兜底
```
### Node.js(fetch + AbortSignal)
```javascript
const API_URL = "https://route.showapi.com/2784-1";
const APP_KEY = "YOUR_APPKEY";
const MAX_RETRY = 3;
async function getPoisonSoup() {
for (let i = 0; i < MAX_RETRY; i++) {
try {
const resp = await fetch(`${API_URL}?appKey=${APP_KEY}`, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
signal: AbortSignal.timeout(5000),
});
const data = await resp.json();
const body = data.showapi_res_body || {};
if (body.ret_code === 0) return body.emposion;
return `毒鸡汤暂时煮糊了(${body.remark || "业务失败"})`;
} catch (e) {
if (i < MAX_RETRY - 1) {
await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 300));
}
}
}
return "服务暂时开小差,稍后再来一句~";
}
```
## 返回示例
```json
{ "showapi_res_body": { "ret_code": -1, "remark": "服务繁忙,请稍后再试", "emposion": "" } }
```
## 进阶/边界
- **只对"可重试"的失败重试**:网络超时/5xx 可重试;`ret_code=-1` 若 `remark` 指向鉴权/参数问题(如 appKey 无效),重试无意义,应直接报错。上例对业务失败做了 `break`,但你也可按 `remark` 关键词细分。
- **免费额度**:每次重试都消耗调用额度,重试上限别设太大;频控见《免费档位下,如何控制毒鸡汤调用频次与成本?》。
- **高并发**:多实例下做重试更要克制,配合队列削峰,详见《高并发》思路与《随机返回的毒鸡汤如何避免重复?》的缓存设计(缓存命中可跳过调用)。
## FAQ
**Q1:能不能把超时设成 10 秒或更长?**
可以设更长,但官方服务端 read/connect 是 5 秒,客户端设更长只是让自己等更久,并不能让服务端多算。建议客户端超时对齐或略大于官方值(如 5~6 秒)。
**Q2:ret_code=-1 要重试吗?**
看 `remark`。若是"服务繁忙"类瞬时错误可有限重试;若是 appKey 无效/过期等硬错误,重试无效应直接告警。不要无差别重试。
**Q3:重试会不会触发限流?**
会。重试计入调用次数,叠加免费档位限制可能导致限流。控制重试上限,并参考频控文章做额度规划。
## 相关能力 / 下一步阅读
- [毒鸡汤生成接口:返回字段全解](https://www.showapi.com/guides/poison-soup-response-2784) —— ret_code/remark 含义
- [随机返回的毒鸡汤如何避免重复?](https://www.showapi.com/guides/poison-soup-dedup-2784) —— 缓存命中跳过调用省额度
- [免费档位下,如何控制毒鸡汤调用频次与成本?](https://www.showapi.com/guides/poison-soup-free-tier-2784) —— 额度与频控
- **本系列共 14 篇**:查看[毒鸡汤生成接口官方指南总目录](https://www.showapi.com/guides/poison-soup-guides-2784)