银行汇率查询:L0 档位每天 100 次,缓存该缓存什么
约 11 分钟 进阶银行汇率查询本地缓存免费档位Redis
# 银行汇率查询:L0 档位每天 100 次,缓存该缓存什么
接口:银行汇率查询(apiCode=105)· 免费接口(L0 基础版 100 次/天、1 QPS)· 请求方式:POST / GET · 返回格式:JSON · 适用人群:已接入、需要控制调用量的开发者 · 阅读时间:约 6 分钟 · 最后实测核对:2026-09-18
## 核心要点
- 免费接口注册即享 L0 基础版,每日 100 次调用、并发 1 QPS,长期有效;100 次摊到一天约等于每 14.4 分钟一次。
- 接口返回的是银行上一周期或上两周期的数据,不是实时汇率,本地缓存几十秒到几分钟对展示效果没有实际影响。
- 缓存键按「接入点 + 货币代码 + 时间窗口」组合,币种列表可以缓存一整天,历史数据按查询参数缓存。
## 100 次够不够用
先把额度算清楚。L0 档位每天 100 次,如果页面每次打开都请求一次牌价,第 100 个访客之后就没有额度了。做成 30 秒轮询更糟,一天就是 2880 次,用量是额度的 28 倍。
所以要决定的是缓存挡在哪一层。牌价本身是延迟数据,用户看不出 60 秒的差别,但调用量会差两个数量级。
## 免费档位与调用限制
2026-09-18 从免费接口页读到的权益档位如下,银行汇率查询(#105)在免费接口列表内:
| 等级 | 每日调用 | 并发 | 获取方式 |
|------|----------|------|----------|
| L0 基础版 | 100 次/天 | 1 QPS | 注册即享,长期有效 |
| L1 进阶版 | 500 次/天 | 5 QPS | 5,000 积分/年 |
| L2 高级版 | 2,000 次/天 | 10 QPS | 15,000 积分/年 |
| L3 专业版 | 10,000 次/天 | 30 QPS | 50,000 积分/年 |
| L4 旗舰版 | 50,000 次/天 | 50 QPS | 100,000 积分/年 |
积分可以通过消费(1 元 = 100 积分)、每日签到(100 积分)、提交反馈、邀请注册等方式获得。档位升级是按年计的,所以缓存策略仍然是第一道防线——升档解决的是上限,缓存解决的是浪费。
## 数据的新鲜度到底是多少
缓存 TTL 定多长,取决于数据本身有多新。产品说明里的表述是:延迟时长无法固定,接口返回为银行上一周期或上两周期的数据,不返回实时汇率;因银行汇率更新无固定时间规则,延迟周期无法明确。接入点文档同时标注「数据源自网络,有数分钟延迟,非投资建议,数据分析参考」。
按这个口径,展示型场景把 TTL 设在 30 到 60 秒,用户看到的内容与不缓存时基本一致。判断缓存里那份数据有多旧,可以读 `list[].day` 和 `list[].time`——实测同一批返回的 46 条记录共用同一个时间戳。
## 内存 TTL 缓存的实现
```python
import time
import threading
import requests
API = "https://route.showapi.com/105-30"
APPKEY = "YOUR_APPKEY"
_cache = {}
_lock = threading.Lock()
# 牌价是延迟数据,30 秒缓存对展示无影响;币种列表可以放长
TTL_RATE = 30
TTL_LIST = 86400
def fetch_rate(code: str = "", ttl: int = TTL_RATE):
key = f"rate:{code or 'ALL'}"
now = time.time()
with _lock:
hit = _cache.get(key)
if hit and now - hit["ts"] < ttl:
return hit["data"]
params = {"appKey": APPKEY}
data = {"code": code} if code else {}
try:
js = requests.post(API, params=params, data=data, timeout=15).json()
if js.get("showapi_res_code") == 0 and js["showapi_res_body"].get("ret_code") == 0:
with _lock:
_cache[key] = {"ts": now, "data": js["showapi_res_body"]}
return js["showapi_res_body"]
except requests.RequestException as exc:
print("请求异常,使用旧缓存兜底:", exc)
# 回源失败时返回上一次成功的结果,避免页面空白
with _lock:
hit = _cache.get(key)
return hit["data"] if hit else None
```
调用 `fetch_rate("USD")` 与 `fetch_rate("USD")` 连续执行两次,只有第一次会真正发出请求。
## 多实例部署用共享缓存
上面那份内存缓存只在单进程内有效。服务多实例部署时,每个实例各存一份,缓存命中率会除以实例数,额度照样被吃掉。把缓存换成 Redis:
```python
import json
import redis
import requests
r = redis.Redis(host="localhost", port=6379, db=0)
API = "https://route.showapi.com/105-30"
APPKEY = "YOUR_APPKEY"
def fetch_rate_shared(code: str = "", ttl: int = 30):
key = f"showapi:105-30:{code or 'ALL'}"
cached = r.get(key)
if cached:
return json.loads(cached)
params = {"appKey": APPKEY}
data = {"code": code} if code else {}
try:
js = requests.post(API, params=params, data=data, timeout=15).json()
except requests.RequestException as exc:
print("请求异常:", exc)
return None
if js.get("showapi_res_code") != 0 or js["showapi_res_body"].get("ret_code") != 0:
return None
body = js["showapi_res_body"]
# 缓存过期时间略短于 TTL,避免多个实例同时回源
r.setex(key, ttl - 5 if ttl > 10 else ttl, json.dumps(body, ensure_ascii=False))
return body
```
## 三种数据的缓存建议
| 数据 | 建议 TTL | 缓存键 | 理由 |
|------|----------|--------|------|
| 实时牌价(105-30) | 30~60 秒 | `105-30:{code}` | 数据本身是延迟快照,秒级新鲜度无实际收益 |
| 币种列表(105-35) | 1 天 | `105-35:list` | 货币集合变动不频繁 |
| 历史牌价(105-34) | 按查询参数长期有效 | `105-34:{code}:{month}` 或 `{code}:{start}~{end}` | 同一天的返回结果不会变化 |
历史数据的关键是把查询参数拼进键里,`month=202608` 和 `month=202607` 是两份不同的缓存,避免相互覆盖。
## FAQ
**Q1:缓存会不会让用户看到过期牌价?**
会,差值就是 TTL 的长度。接口返回的是银行上一周期或上两周期的延迟数据,几十秒的缓存对展示场景没有实际影响。如果业务对新鲜度更敏感,把 TTL 调小即可。
**Q2:L0 档位每天具体能调多少次?**
100 次/天,并发 1 QPS,注册即享,长期有效。需要通过平台积分升级到 L1~L4 才能提高,具体额度见免费接口页。
**Q3:100 次以外的调用会怎样?**
超出当前档位的调用按官方档位说明处理。把缓存与限流做在前面,日常调用量就会留在档位以内。
**Q4:单机的内存缓存够用吗?**
单进程、小流量够用。多实例部署必须换成 Redis 这类共享缓存,否则每个实例各自回源,缓存等于没做。
**Q5:回源失败时怎么保证页面不空白?**
返回上一次成功缓存的结果,同时在界面上提示数据可能不是最新的。上面的 `fetch_rate` 已经包含这个兜底分支。
**Q6:缓存能省钱吗?**
本接口免费,不存在按次扣费,缓存省的是每日调用额度与并发占用。
## 下一步阅读
- [银行汇率查询并发怎么控?纯同步模型下的限流思路](https://www.showapi.com/guides/exchange-rate-concurrency-105):缓存之外的另一个调用量控制手段。
- [银行汇率查询:数据延迟与「仅供参考」的四个适用范围](https://www.showapi.com/guides/exchange-rate-delay-caveat-105):TTL 该定多长的依据。
- [银行汇率查询历史汇率:按月取还是按区间取](https://www.showapi.com/guides/exchange-rate-history-guide-105):历史数据的查询参数与缓存键设计。
- **本系列共 13 篇**:查看[银行汇率查询指南总目录](https://www.showapi.com/guides/exchange-rate-guides-105)





