技术博客
免费接口也别乱调用:童话故事集 API 内容缓存与分页拉取策略

免费接口也别乱调用:童话故事集 API 内容缓存与分页拉取策略

作者: 万维易源
2026-09-02
缓存策略分页拉取Redis限流
# 免费接口也别乱调用:童话故事集 API 内容缓存与分页拉取策略 > 元信息:童话故事集 API(apiCode=1700)· 全接入点 · 免费服务 · 适用人群:已接入、准备上线的中高级开发者 · 阅读时间约 8 分钟 ## 核心要点 - 分类(1700-1)与详情正文(1700-3)变化频率极低,适合做小时级甚至天级缓存。 - 列表(1700-2)按「分类+关键字」做短时效缓存,分页靠 `allPages` 顺序翻页。 - 免费服务有档次限制,缓存 + 限流能显著降低调用量、避免超限。 ## Why:免费≠可以随便打 童话故事集 API 虽然是免费接口,但"免费"靠使用档次限制来兜底——高频、批量的循环调用很容易触顶。故事内容本身几乎不变(经典童话不会天天改),所以最划算的做法是把内容缓存起来,只在必要时回源。本篇给出可落地的缓存键设计与分页拉取写法。 ## What:缓存价值速览 | 接入点 | 数据特征 | 建议缓存 | |--------|----------|----------| | 1700-1 分类 | 极稳定 | 缓存数小时~1 天 | | 1700-2 列表 | 随分类+关键字变化 | 缓存数分钟~数十分钟(按 key) | | 1700-3 详情 | 正文几乎不变 | 缓存数天~永久(按 id) | ## How:缓存键设计与分页拉取 ### 1. 用 Redis 缓存详情(按 id) ```python import requests, json, redis rds = redis.Redis() APPKEY = "YOUR_APPKEY" def get_story(story_id): cache_key = f"story:detail:{story_id}" cached = rds.get(cache_key) if cached: return json.loads(cached) # 命中缓存,不回源 r = requests.post(f"https://route.showapi.com/1700-3?appKey={APPKEY}", data={"id": story_id}, headers={"content-type": "application/x-www-form-urlencoded"}, timeout=10) body = r.json()["showapi_res_body"] if body.get("ret_code") != "0": raise SystemExit(body.get("remark")) rds.set(cache_key, json.dumps(body, ensure_ascii=False), ex=86400 * 7) # 缓存 7 天 return body ``` ```javascript const redis = require("redis"); const rds = redis.createClient(); const APPKEY = "YOUR_APPKEY"; async function getStory(storyId) { const key = `story:detail:${storyId}`; const hit = await rds.get(key); if (hit) return JSON.parse(hit); const r = await fetch(`https://route.showapi.com/1700-3?appKey=${APPKEY}`, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ id: storyId }), }); const body = (await r.json()).showapi_res_body; if (body.ret_code !== "0") throw new Error(body.remark); await rds.set(key, JSON.stringify(body), "EX", 86400 * 7); return body; } ``` ### 2. 列表分页拉全(带限流) ```python import time def fetch_all(classify_id, keyword): page, out = 1, [] while True: r = requests.post(f"https://route.showapi.com/1700-2?appKey={APPKEY}", data={"classifyId": classify_id, "keyword": keyword, "page": str(page)}, headers={"content-type": "application/x-www-form-urlencoded"}, timeout=10) body = r.json()["showapi_res_body"] out.extend(body["contentlist"]) if page >= int(body["allPages"]): break page += 1 time.sleep(0.2) # 控制频率,避免触档次限制 return out ``` ## 返回示例与解析 分页关键字段(1700-2 返回 `showapi_res_body` 内): ```json { "allNum": "15", "allPages": "1", "currentPage": "1", "maxResult": "20" } ``` 循环条件 `page >= int(allPages)` 即可拉完全部分页,无需猜页数。 ## 进阶 / 边界 - **缓存失效策略**:详情正文若需更新(如纠错),用固定 TTL(如 7 天)自然过期,或主动 `DEL story:detail:{id}` 强制刷新。 - **列表缓存 key 要带全维度**:`story:list:{classifyId}:{keyword}:{page}`,否则不同分类/关键字会串数据。 - **限流兜底**:除缓存外,建议加令牌桶/信号量控制每秒请求数,超限时退避重试(指数退避)。 ## FAQ **Q: 缓存 7 天,内容更新了怎么办?** A: 详情内容极稳定,7 天 TTL 后自然回源;若需即时更新,主动删除该 id 的缓存键即可。 **Q: 列表缓存多久合适?** A: 列表比详情变化快,建议数分钟到数十分钟短缓存,且 key 必须包含 classifyId+keyword+page。 **Q: 免费接口也会限流吗?** A: 会。免费服务靠使用档次限制兜底,具体阈值以官方说明为准;缓存+限流是最有效的规避手段(见[免费档位说明](https://www.showapi.com/guides/child-story-free-tier-1700))。 **Q: 能不能一次性拉全部故事建库?** A: 没有批量接入点,只能逐级调用。建库时务必分页+限流+缓存,否则易超限。 ## 相关能力 / 下一步阅读 - [童话故事集 API 免费档位说明](https://www.showapi.com/guides/child-story-free-tier-1700) - [童话故事集 API:故事列表搜索与分页实战](https://www.showapi.com/guides/child-story-list-guide-1700) - [儿童故事小程序全链路设计](https://www.showapi.com/guides/child-story-list-integration-1700) - **本系列共 12 篇**:查看[童话故事集 API 指南总目录](https://www.showapi.com/guides/child-story-guides-1700)