免费接口也要缓存:常见疾病查询的静态科室树与明细缓存策略
# 免费接口也要缓存:常见疾病查询的静态科室树与明细缓存策略
> 接口:常见疾病查询(apiCode=546)· 免费 · 请求方式 POST/GET · 返回格式 JSON · 适用人群:已接入开发者、架构师 · 阅读时间:约 7 分钟
## 核心要点
- 本接口**免费**,缓存的目的不是"省钱"(无按次扣费),而是**提升响应速度、降低对外部接口的实时依赖、增强可用性**。
- 546-1 科室树几乎静态 → 长缓存/落库;546-3 明细按 `id` 缓存;546-2 检索可按 query 短缓存。
- 课本级做法:内存/Redis 缓存 + key 设计 + 失效策略 + 失败降级(缓存兜底)。
## Why:免费也要缓存
很多人觉得"免费接口随便调",但生产环境里每一跳外部请求都意味着:延迟、限频风险、以及接口偶发不可用时你的功能跟着挂。常见疾病查询的数据特征非常适合缓存:
- 科室分类(546-1)长期不变;
- 疾病知识(546-3 明细)相对稳定;
- 只有检索(546-2)偏动态,但同 query 重复率高。
合理缓存后,你的导诊/知识库首页基本不依赖实时外网,体验更稳更快。
## What:各接入点缓存建议
| 接入点 | 数据特征 | 缓存策略 |
|--------|---------|---------|
| 546-1 科目树 | 几乎静态 | 长缓存(如 7 天)/ 落库,启动时预热 |
| 546-2 关键字检索 | 偏动态、同 query 复用高 | 短缓存(如 1~6 小时),key=查询参数哈希 |
| 546-3 疾病明细 | 相对稳定 | 中长缓存(如 1~7 天),key=`id` |
## How:生产级缓存(Redis 示例)
```python
import redis, hashlib, json
r = redis.Redis(host="localhost", port=6379, db=0)
TTL_TREE = 7 * 86400
TTL_DETAIL = 86400
TTL_SEARCH = 3600
def cached_call(point, ttl, key_suffix="", **params):
cache_key = f"disease:{point}:{key_suffix}"
hit = r.get(cache_key)
if hit:
return json.loads(hit)
body = call(point, **params) # 见快速开始的统一 call()
r.setex(cache_key, ttl, json.dumps(body, ensure_ascii=False))
return body
# 科室树:长缓存
tree = cached_call("546-1", TTL_TREE, "tree")
# 明细:按 id 缓存
detail = cached_call("546-3", TTL_DETAIL, disease_id, id=disease_id)
# 检索:按参数哈希短缓存
q = hashlib.md5("3|高血压|1".encode()).hexdigest()
hits = cached_call("546-2", TTL_SEARCH, q, typeId="3", key="高血压", page="1")
```
### 失败降级(缓存兜底)
```python
def safe_detail(disease_id):
try:
return cached_call("546-3", TTL_DETAIL, disease_id, id=disease_id)
except Exception:
# 外部接口不可用时,回退到上次缓存(即使已过期)
raw = r.get(f"disease:546-3:{disease_id}")
if raw:
return json.loads(raw)
raise # 实在没有则向上抛,由 UI 给出"暂不可用"
```
### cURL(无缓存,仅示意实时调用)
```bash
curl -X POST "https://route.showapi.com/546-3?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" \
--data-urlencode "id=<疾病id>"
```
### Node.js(fetch + 内存缓存示意)
```javascript
const cache = new Map();
async function cachedCall(point, key, ttl, params) {
if (cache.has(key)) return cache.get(key);
const data = await call(point, params);
cache.set(key, data);
setTimeout(() => cache.delete(key), ttl * 1000);
return data;
}
```
## 返回示例与解析
缓存的 value 即接口原生 `showapi_res_body`(含 `list`/`contentlist`/`item`),命中缓存时直接复用,不再发外网请求。
## 进阶 / 边界
- **免费≠无限**:免费服务通常有调用频率约束,缓存能显著降低请求数,避免触限(频率以官方说明为准)。
- **失效策略**:科室树可设很长 TTL 甚至落库定时刷新;明细变化慢可 1~7 天;检索按需短缓存。
- **降级优先**:外部不可用时,过期缓存兜底比直接报错体验好,但需在 UI 标注"数据可能非最新"。
- **key 设计**:检索缓存 key 用「参数组合哈希」,避免不同查询串味。
## FAQ
**Q1:免费接口缓存能省什么?**
A:省的是响应延迟与外部依赖风险,不是钱(本接口不按次扣费)。
**Q2:缓存多久合适?**
A:科室树可 7 天/落库;明细 1~7 天;检索 1~6 小时。以数据实际更新频率调整。
**Q3:接口挂了缓存能顶多久?**
A:取决于 TTL 与降级策略;建议过期缓存兜底 + UI 标注"数据可能非最新"。
**Q4:检索结果要缓存吗?**
A:同 query 复用率高,建议短缓存(key=参数哈希),既提速又降频。
## 相关能力 / 下一步阅读
- [常见疾病查询:医院科室分类全量清单(含 typeId / subId 映射)](https://www.showapi.com/guides/disease-query-department-list-546)
- [常见疾病查询:取得疾病明细并解析症状/诊断/治疗/预防(546-3 的 tagList)](https://www.showapi.com/guides/disease-query-detail-546)
- [常见疾病查询常见问题与 ret_code 排查:0 为成功、非 0 即失败](https://www.showapi.com/guides/disease-query-faq-546)
- **本系列共 12 篇**:查看[常见疾病查询指南总目录](https://www.showapi.com/guides/disease-query-guides-546)