技术博客
历史上的今天:免费接口下如何做本地缓存与更新频率设计?

历史上的今天:免费接口下如何做本地缓存与更新频率设计?

作者: 万维易源
2026-08-31
历史上的今天本地缓存Redis免费接口
# 历史上的今天:免费接口下如何做本地缓存与更新频率设计? > 接口:历史上的今天(apiCode=119,接入点 119-42)· 免费(设防滥用档位)· 适用人群:中高级开发者 · 阅读时间:约 6 分钟 ## 核心要点 - 历史数据"按天稳定":同一 `date` 的结果当天基本不变,天然适合按 `date` 缓存。 - 缓存 key 用 `date`(MMDD),每日 0 点失效;命中缓存就不调接口,免费额度花在刀刃上。 - 服务端每日定时预热 + 前端读本地缓存,是教育/网站场景的标准姿势。 ## Why:免费但不等于可以乱刷 虽然是免费接口,但设有防滥用档位。如果你的网站每天被访问几万次,每次都去调接口,既可能触档位限制,也拖慢自身响应。历史数据按天稳定——今天 2 月 20 日的结果,这一天内不会变。把"按天"作为缓存粒度,一次拉取、全天复用,体验与额度双优。 ## What:缓存设计要点 | 维度 | 建议 | |------|------| | 缓存粒度 | 以 `date`(MMDD)为 key,单日一份 | | 失效策略 | 自然日 0 点失效(TTL 到次日 00:00) | | 存储 | 内存(LRU)/ Redis / 本地 JSON 文件均可 | | 预热 | 服务端每日定时(如 00:05)拉取"今天"入库 | | 档位 | 具体限额以官方档位说明为准,不编造数字 | ## How:三种缓存实现 ### 1)Python + 内存(简单服务) ```python import requests, datetime, time _cache = {} def get_history(date: str = None): date = date or datetime.date.today().strftime("%m%d") if date in _cache: return _cache[date] # 命中缓存 url = "https://route.showapi.com/119-42" params = {"appKey": "YOUR_APPKEY"} data = {"date": date, "needContent": "1"} resp = requests.post(url, params=params, data=data, timeout=10) body = resp.json()["showapi_res_body"] # 计算到次日 00:00 的 TTL now = datetime.datetime.now() ttl = (now.replace(hour=0, minute=0, second=0, microsecond=0) + datetime.timedelta(days=1) - now).seconds _cache[date] = (time.time() + ttl, body["list"]) return body["list"] def get_history_safe(date=None): ts, data = get_history(date) if time.time() > ts: _cache.pop(date or datetime.date.today().strftime("%m%d"), None) return get_history(date) return data ``` ### 2)Redis(多实例共享) ```python import redis, json, datetime, requests r = redis.Redis(host="localhost", port=6379, db=0) def get_history_redis(date: str = None): date = date or datetime.date.today().strftime("%m%d") cached = r.get(f"history:{date}") if cached: return json.loads(cached) url = "https://route.showapi.com/119-42" params = {"appKey": "YOUR_APPKEY"} data = {"date": date, "needContent": "1"} body = requests.post(url, params=params, data=data, timeout=10).json()["showapi_res_body"] # 过期时间设为到次日 00:00 now = datetime.datetime.now() ttl = (now.replace(hour=0, minute=0, second=0, microsecond=0) + datetime.timedelta(days=1) - now).seconds r.setex(f"history:{date}", ttl, json.dumps(body["list"], ensure_ascii=False)) return body["list"] ``` ### 3)Node.js(fetch + Map) ```javascript const cache = new Map(); function ttlToMidnight() { const now = new Date(); const next = new Date(now); next.setHours(24, 0, 0, 0); return next - now; } async function getHistory(date) { date = date || new Date().toISOString().slice(5, 10).replace("-", ""); if (cache.has(date)) return cache.get(date); const url = `https://route.showapi.com/119-42?appKey=YOUR_APPKEY`; const body = new URLSearchParams({ date, needContent: "1" }); const resp = await fetch(url, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body }); const list = (await resp.json()).showapi_res_body.list; cache.set(date, list); setTimeout(() => cache.delete(date), ttlToMidnight()); return list; } ``` ## 返回示例与解析 缓存命中时直接返回上次存入的 `list` 数组(结构同[返回字段篇](https://www.showapi.com/guides/history-today-response-fields-119)),不再发请求。 ## 进阶 / 边界 - **不要按"每次请求"缓存**:粒度应是 `date`,不是用户会话。同一天所有用户共享一份。 - **TTL 用"次日 0 点"**:比固定 24h 更准,避免跨日仍显示旧日期。 - **预热优于冷启动**:服务端定时任务在 0 点后主动拉一次,用户首次访问即命中,无首屏延迟。 - **档位未知不猜**:具体免费调用上限以官方档位说明为准;缓存正是为把调用次数压到"每天每日期望 1 次"。 ## FAQ **Q1:缓存 key 用什么?** 用 `date`(MMDD)。同一天结果稳定,按天缓存最合理。 **Q2:多久失效一次?** 建议到次日 00:00 失效,而不是固定 24 小时。 **Q3:多个服务器实例怎么共享缓存?** 用 Redis 等集中存储,key 统一为 `history:{date}`。 **Q4:免费接口还有必要缓存吗?** 有必要。防滥用档位 + 自身响应速度,都靠"每天每日期望只调一次"来保障。 ## 相关能力 / 下一步阅读 - [历史上的今天:date 参数用法(MMDD 格式、默认今天、跨年边界)实战指南](https://www.showapi.com/guides/history-today-date-param-119) — `date` 格式与默认值。 - [历史上的今天:教育/课堂场景如何集成历史事件 API?](https://www.showapi.com/guides/history-today-education-119) — 每日入库存哪里。 - [历史上的今天:网站/App 每日历史卡片组件集成指南](https://www.showapi.com/guides/history-today-widget-119) — 组件读缓存。 - **本系列共 10 篇**:查看[历史上的今天指南总目录](https://www.showapi.com/guides/history-today-guides-119)