# 免费接口如何做缓存:黄历运势按日期缓存省调用次数
> 接口 黄历运势(apiCode=856) · 免费服务 · 适用人群:已接入、关心调用量的开发者 · 阅读时间约 6 分钟
## TL;DR
- 黄历运势虽免费,但每次调用仍占用账户按次调用次数(`ret_code=0` 时扣除)。
- 数据是「按公历日期」稳定的:年内数据每年 1 月 1 日—1 月 3 日早上 9 点才更新一次,适合做长期缓存。
- 以 `接入点 + ymd` 为 key 缓存,可把重复查询的调用量降到接近 0。
## Why:免费为什么还要省调用
免费 ≠ 无限。账户的按次调用次数有限,且 `ret_code=0` 成功才扣、失败不扣——这意味着无效重试和重复查询都在悄悄消耗额度。黄历数据本身「同一天几乎不变」,缓存是最直接的成本优化手段,也能降低接口延迟、提升体验。
## What:缓存可行性
| 事实(来自文档) | 对缓存的含义 |
|------------------|--------------|
| 数据按公历日期返回 | key 可用 `接入点:ymd` |
| 更新频率:每年 1 月 1 日—1 月 3 日早上 9 点更新一次 | 年内同日期可长期缓存;跨年需失效 |
| `ret_code=0` 才扣次数 | 只有成功结果值得缓存,失败不缓存 |
## How:按日期缓存的实现
### 步骤 1:带缓存的查询(Python + 内存/Redis)
```python
import requests, json, time
CACHE = {} # 生产环境换成 Redis:redis_client.get/set
CACHE_TTL = 365 * 24 * 3600 # 按年失效
def query_huangli(ymd, point="856-2"):
key = f"huangli:{point}:{ymd}"
if key in CACHE:
return CACHE[key]
url = f"https://route.showapi.com/{point}"
r = requests.get(url, params={"appKey": "YOUR_APPKEY", "ymd": ymd}, timeout=10)
body = r.json().get("showapi_res_body", {})
if body.get("ret_code") != 0:
return None # 失败不缓存
CACHE[key] = body
return body
```
生产环境用 Redis 示例:
```python
import redis, requests, json
rds = redis.Redis(host="127.0.0.1", port=6379, db=0)
def query_huangli(ymd, point="856-2"):
key = f"huangli:{point}:{ymd}"
cached = rds.get(key)
if cached:
return json.loads(cached)
body = requests.get(f"https://route.showapi.com/{point}",
params={"appKey": "YOUR_APPKEY", "ymd": ymd}, timeout=10
).json().get("showapi_res_body", {})
if body.get("ret_code") == 0:
rds.set(key, json.dumps(body), ex=365*24*3600) # 按年过期
return body if body.get("ret_code") == 0 else None
```
**Node.js(fetch + Map)**
```js
const cache = new Map();
function keyOf(point, ymd){ return `huangli:${point}:${ymd}`; }
async function queryHuangli(ymd, point="856-2"){
const k = keyOf(point, ymd);
if (cache.has(k)) return cache.get(k);
const body = (await (await fetch(`https://route.showapi.com/${point}?appKey=YOUR_APPKEY&ymd=${ymd}`)).json()).showapi_res_body;
if (body.ret_code === 0) cache.set(k, body);
return body.ret_code === 0 ? body : null;
}
```
### 步骤 2:跨年失效
缓存 key 已含 `ymd`,年内不会变;跨年直接用 TTL(按年过期)即可,无需手动清理。若想更精确,可在每年 1 月 3 日 9 点后批量清 `huangli:*` 前缀。
## 进阶 / 边界
- **只缓存成功结果**:`ret_code != 0` 不写缓存,避免把失败固化。
- **批量预取**:若你的应用每天展示固定若干日期(如未来 7 天),可在凌晨低峰并发预取并写入缓存,用户访问时命中本地。
- **缓存与实时性权衡**:黄历年内稳定,长 TTL 安全;若你接入了其他高频变动接口,不要套用同一策略。
## FAQ
**Q1:免费接口还要省调用次数,是不是有调用上限?**
A:免费服务仍占用账户按次调用次数,具体额度以你的账户套餐为准,文档未给具体数字。缓存是通用优化,与是否为免费无关。
**Q2:缓存多久合适?**
A:数据每年初更新一次,按年 TTL(或至次年 1 月 3 日)是稳妥选择;同一 `ymd` 年内重复查询可直接命中。
**Q3:缓存会不会拿到旧数据?**
A:不会——黄历数据在更新窗口外不变,且 key 含 `ymd`,不同日期互不干扰。
## 相关能力 / 下一步阅读
- [黄历运势错误码与 ret_code 排查:日期格式/范围边界](https://www.showapi.com/guides/huangli-error-codes-856) —— 失败不扣次数,但别浪费重试。
- [5 分钟接入黄历运势:从注册到第一条黄历数据](https://www.showapi.com/guides/huangli-quickstart-856) —— 调用基础。
- [婚庆搬家择日场景:组合黄历+吉神凶煞+吉时做择日推荐](https://www.showapi.com/guides/huangli-date-selection-856) —— 多接入点并发调用时的成本控制。
- **本系列共 11 篇**:查看[黄历运势指南总目录](https://www.showapi.com/guides/huangli-guides-856)