绕口令与谜语查询:免费档位下的调用纪律与本地缓存策略
# 绕口令与谜语查询:免费档位下的调用纪律与本地缓存策略
**接口**:绕口令与谜语查询(apiCode=1623)· 接入点 1623-1 / 1623-2|**是否免费**:免费(含使用档次限制)|**返回格式**:JSON|**适用人群**:已接入、准备上生产的开发者|**阅读时间**:约 6 分钟
## 核心要点
- 本接口是**免费服务但设有使用档次限制**(防滥用),文档未给出具体档位数字——额度以[官方档位说明](https://www.showapi.com/free-api)为准,本文不编造。
- 缓存是守住免费额度、避免被限流的最直接手段:以「接入点 + 关键词 + page」为 key,命中即返回、不调接口。
- 缓存 TTL 建议按「内容更新频率」设定;文档标注「数据持续更新中」,可设较短 TTL(如数小时~1 天)兼顾新鲜度与省量。
## Why:免费 ≠ 无限,省着用才长久
免费接口的档次限制是为了防止滥用。你的每一次重复查询(同一关键词翻同一页、全班同时刷新、前端轮询)都在消耗额度。用本地缓存把「重复请求」挡在本地,既快又省,还能在接口抖动时兜底。
## What:缓存什么、以什么为 key
| 维度 | 建议 |
|------|------|
| 缓存 key | `接入点 + 关键词 + page`(如 `1623-1:扁担:1`) |
| 缓存 value | 整个 `contentlist`(或整页 `showapi_res_body`) |
| TTL | 数小时~1 天;内容更新频繁可更短 |
| 落库位置 | 服务端内存/Redis,或前端静态 JSON(活动场景) |
## How:带缓存的查询(Python + 简单内存/文件缓存)
```python
import json, time, requests
APP_KEY = "YOUR_APPKEY"
CACHE_FILE = "tongue_riddle_cache.json"
TTL = 3600 * 6 # 6 小时
_cache = {}
def load_cache():
try:
with open(CACHE_FILE, "r", encoding="utf-8") as f:
return json.load(f)
except FileNotFoundError:
return {}
def save_cache(c):
with open(CACHE_FILE, "w", encoding="utf-8") as f:
json.dump(c, f, ensure_ascii=False)
def cached_query(point: str, keyword: str, page: int = 1):
global _cache
_cache = load_cache()
key = f"{point}:{keyword}:{page}"
now = time.time()
hit = _cache.get(key)
if hit and now - hit["ts"] < TTL:
return hit["body"] # 命中,不调接口
url = f"https://route.showapi.com/{point}"
timeout = 5 if point == "1623-1" else 15
resp = requests.post(
url,
params={"appKey": APP_KEY},
data={"title" if point == "1623-1" else "question": keyword, "page": str(page)},
timeout=timeout,
)
body = resp.json()["showapi_res_body"]
_cache[key] = {"ts": now, "body": body}
save_cache(_cache)
return body
```
**Node.js(fetch + Map 内存缓存)**
```javascript
const APP_KEY = "YOUR_APPKEY";
const TTL = 6 * 3600 * 1000;
const cache = new Map();
async function cachedQuery(point, keyword, page = 1) {
const key = `${point}:${keyword}:${page}`;
const hit = cache.get(key);
if (hit && Date.now() - hit.ts < TTL) return hit.body;
const url = `https://route.showapi.com/${point}?appKey=${APP_KEY}`;
const param = point === "1623-1" ? "title" : "question";
const body = new URLSearchParams({ [param]: keyword, page: String(page) });
const resp = await fetch(url, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body,
signal: AbortSignal.timeout(point === "1623-1" ? 5000 : 15000),
});
const resBody = (await resp.json()).showapi_res_body;
cache.set(key, { ts: Date.now(), body: resBody });
return resBody;
}
```
## 返回示例与解析
缓存命中时直接复用历史 `showapi_res_body`,结构同[返回字段全解](https://www.showapi.com/guides/tongue-riddle-response-fields-1623);未命中才真正发起请求。
## 进阶 / 边界
- **空结果也缓存**:无匹配的 `contentlist` 为空仍是有效响应,可缓存避免反复空查(但 TTL 设短些,内容可能更新)。
- **TTL 取舍**:文档说「数据持续更新中」,TTL 过长会拿到旧内容;按业务容忍度设 1 小时~1 天。
- **服务端 vs 前端**:服务端 Redis 缓存对全用户生效、最省量;纯前端缓存只省本机,适合活动/离线场景。
- **防滥用另一面**:前端侧限流见[前端限流与防滥用](https://www.showapi.com/guides/tongue-riddle-frontend-throttle-1623)。
## FAQ
**Q1:免费额度到底有多少?**
A:文档仅说明「免费 + 使用档次限制(防滥用)」,未给具体数字;以[官方档位说明](https://www.showapi.com/free-api)为准,本文不编造。
**Q2:缓存会让内容变旧吗?**
A:会,TTL 越长越旧;文档称数据持续更新,建议 TTL 控制在数小时~1 天。
**Q3:缓存 key 要包含 page 吗?**
A:要。不同页返回不同内容,key 必须含「接入点 + 关键词 + page」,否则串数据。
**Q4:被限流了怎么恢复?**
A:以降低频率 + 提高缓存命中为主;具体恢复规则以官方档位说明为准。
**Q5:能用 CDN/网关层缓存吗?**
A:可以,GET 形式且参数固定的请求适合边缘缓存;注意 AppKey 不要进公共缓存 key 暴露。
## 下一步阅读
- [绕口令与谜语查询:错误处理与 ret_code 排查](https://www.showapi.com/guides/tongue-riddle-error-handling-1623)
- [绕口令与谜语查询:分页遍历指南](https://www.showapi.com/guides/tongue-riddle-pagination-1623)
- [绕口令与谜语查询:前端限流与防滥用实践](https://www.showapi.com/guides/tongue-riddle-frontend-throttle-1623)
- **本系列共 12 篇**:查看[绕口令与谜语查询指南总目录](https://www.showapi.com/guides/tongue-riddle-guides-1623)