# 免费接口也要稳:歇后语查询本地缓存与去重策略
- **接口/接入点**:歇后语查询 · 1635-1
- **是否免费**:是
- **请求方式**:POST / GET
- **返回格式**:JSON
- **适用人群**:中高级开发者、做"每日一语"/答题类产品的工程师
- **阅读时间**:约 7 分钟
## 核心要点
- 底层语料有限(`allNum` 示例 19),随机易重复;本地缓存 + 去重是体验关键。
- 缓存 key 建议用 `question` 做唯一标识,已用集合放内存或 Redis。
- 免费接口也有档次限制,缓存能直接减少调用次数。
## Why:免费接口为什么还要缓存
"每日一语"连出同一条、"答题卡"前一题后一题一样,体验直接崩。而且免费接口设使用档次限制,能少打一次是一次。本地缓存 + 去重,既稳体验又省调用。
## What:缓存目标
| 目标 | 做法 |
|------|------|
| 不去重 | 每次随机取,可能撞车 |
| 去重 | 维护已用集合,撞了重拉(带重试上限) |
| 省调用 | 落库/内存缓存,前端读缓存而非实时打接口 |
## How:Redis 去重设计
### key 结构
```
xiehouyu:used:set -> 已用 question 集合(Set)
xiehouyu:daily:{date} -> 当天已展示的 question(可设过期)
```
### Python 示例
```python
import redis, requests, datetime
rds = redis.Redis(host="localhost", port=6379, db=0)
def draw_unique(n=1, max_try=20):
got, tries = [], 0
while len(got) < n and tries < max_try:
tries += 1
resp = requests.post("https://route.showapi.com/1635-1",
params={"appKey": "YOUR_APPKEY"},
data={"num": str(n * 2)}, timeout=15)
body = resp.json()["showapi_res_body"]
if body.get("ret_code") != "0":
break
for it in body["contentlist"]:
key = it["question"]
if not rds.sismember("xiehouyu:used:set", key) and it not in got:
got.append(it); rds.sadd("xiehouyu:used:set", key)
if len(got) >= n:
break
return got
# 每天重置当日展示集合,长期去重仍靠 used:set
today = datetime.date.today().isoformat()
for it in draw_unique(1):
rds.sadd(f"xiehouyu:daily:{today}", it["question"])
```
### 前端读缓存
前端只读自己后端缓存/数据库,不直接打接口(也避免 AppKey 泄露)。
## 返回示例与解析
返回结构同其他篇:`contentlist` 数组,`question` 作为去重主键最合适(谜底可能重复,谜面基本唯一)。
## 进阶 / 边界
- **语料见底怎么办**:`allNum` 有限,长期运行 `used:set` 会填满;可定期(如每月)清空或重置,接受循环。
- **重试上限**:去重重试要有上限,避免语料耗尽时死循环。
- **频率**:定时任务每天 1 次即可,结合缓存完全够用。
## FAQ
**Q:用 question 还是 answer 做去重 key?**
A:用 `question`(谜面)做主键更稳,谜底可能雷同。
**Q:语料用完了会怎样?**
A:`used:set` 填满后去重抽不到新题,需设重试上限并定期重置集合,接受循环。
**Q:缓存能省多少调用?**
A:每日一语类场景从"每次打开都打"变成"每天 1 次",量级下降明显;具体以你的访问量定。
**Q:一定要 Redis 吗?**
A:不一定,内存集合/SQLite 也可;多实例部署才需要 Redis 这类共享存储。
**Q:免费档位会被缓存打爆吗?**
A:缓存是减少调用,反而更不容易触限;具体档位以官方说明为准。
## 相关能力 / 下一步阅读
- [歇后语查询 num 参数详解:随机条数、maxResult 与返回上限](https://www.showapi.com/guides/xiehouyu-num-param-1635)
- [歇后语查询错误处理:ret_code / showapi_res_code 与重试指南](https://www.showapi.com/guides/xiehouyu-error-handling-1635)
- **本系列共 13 篇**:查看[歇后语查询指南总目录](https://www.showapi.com/guides/xiehouyu-guides-1635)