# 地区新闻接口免费档位限制:限流、重试与退避策略
> 接口/接入点:地区新闻接口(apiCode 170)|免费 · POST/GET · 返回 JSON · 适用人群:已接入用户、后端开发者 · 阅读时间:约 6 分钟
## 核心要点
- 接口免费,但文档明确"为防止滥用设有使用档次限制",具体档位以 https://www.showapi.com/free-api 为准(本文不编造数字)。
- 生产环境务必加限流(令牌桶)+ 失败指数退避重试 + 失败兜底,避免触发限流或雪崩。
- 配合缓存(见分页缓存篇)能从源头削减调用量,是应对档位限制的第一道防线。
## Why:免费更要有"工程化"的稳
免费接口的最大风险不是"要钱",而是"被限流"——一旦超过档位,请求会被拒,页面瞬间空白、用户投诉。把限流、重试、兜底做扎实,比单纯"多调几次"可靠得多。本文给你一套可直接抄的生产级写法。
## What:官方事实边界
| 项 | 说明 |
|------|------|
| 计费 | 免费服务 |
| 限制 | 注册后默认可用,设有使用档次限制(防滥用) |
| 具体数字 | 文档未给,以 https://www.showapi.com/free-api 的官方档位说明为准 |
| 本文立场 | 不杜撰调用量/档位数值,只给工程化应对方案 |
## How:限流 + 退避 + 兜底
### 令牌桶限流(Python)
```python
import time, threading, requests
class TokenBucket:
def __init__(self, rate, capacity):
self.rate=rate; self.capacity=capacity; self.tokens=capacity
self.lock=threading.Lock(); self.last=time.time()
def acquire(self):
with self.lock:
now=time.time(); self.tokens=min(self.capacity, self.tokens+(now-self.last)*self.rate)
self.last=now
if self.tokens>=1:
self.tokens-=1; return True
return False
bucket = TokenBucket(rate=5, capacity=10) # 示例:每秒 5 个,峰值 10
def safe_call(area_id, page=1, max_retry=3):
for attempt in range(max_retry):
if not bucket.acquire():
time.sleep(0.2); continue
try:
r=requests.post("https://route.showapi.com/170-47",
params={"appKey":"YOUR_APPKEY"},
data={"areaId":area_id,"page":page},
headers={"content-type":"application/x-www-form-urlencoded"}, timeout=10)
body=r.json()["showapi_res_body"]
if body.get("ret_code")!="0":
raise RuntimeError("业务失败")
return body["pagebean"]["contentlist"]
except Exception as e:
wait=min(2**attempt, 8) # 指数退避,封顶 8s
time.sleep(wait)
return None # 兜底:返回空,由上层展示缓存或占位
```
### Node.js 指数退避重试
```js
async function safeCall(areaId, page=1, maxRetry=3){
for(let i=0;i<maxRetry;i++){
try{
const r=await fetch("https://route.showapi.com/170-47?appKey=YOUR_APPKEY",{
method:"POST", headers:{"content-type":"application/x-www-form-urlencoded"},
body:new URLSearchParams({areaId, page})
});
const d=await r.json();
if(d.showapi_res_body.ret_code!=="0") throw new Error("fail");
return d.showapi_res_body.pagebean.contentlist;
}catch(e){
if(i===maxRetry-1) return null;
await new Promise(r=>setTimeout(r, Math.min(2**i, 8000)));
}
}
}
```
## 返回示例与解析
本篇无新增返回结构;重点在"调用层"行为:成功返回 `contentlist`,失败/限流时按退避重试,最终兜底返回 `null`,上层用缓存或占位图承接。
## 进阶 / 边界
- **档位数字不可臆测**:本文所有"示例数值"(如 rate=5)仅为演示代码可用性,真实配额以官方档位页为准。
- **失败兜底优先用缓存**:`safe_call` 返回 `null` 时,优先回退到本地缓存的旧数据,保证页面不空白。
- **批量聚合场景**:后台错峰 + 缓存预热(见本地聚合篇)比前台实时高并发更稳。
## FAQ
**Q:免费档位具体是多少次/天?**
A:文档未给出具体数字,仅说明"设有使用档次限制",请以 https://www.showapi.com/free-api 的官方说明为准,本文不编造。
**Q:被限流了会返回什么?**
A:以系统返回为准;无论何种形式,本篇的令牌桶+退避+兜底都能平滑承接,避免雪崩。
**Q:缓存能完全避免限流吗?**
A:能大幅削减调用量,但首次加载、缓存失效、不同地区的首次请求仍会产生调用,因此仍需限流与重试做保险。
## 相关能力与下一步阅读
- [地区新闻接口分页与缓存策略:每页 20 条、10 分钟更新怎么省调用](https://www.showapi.com/guides/region-news-pagination-170)
- [地区新闻接口实战:用地区新闻搭建本地资讯聚合看板](https://www.showapi.com/guides/region-news-local-aggregator-170)
- **本系列共 12 篇**:查看[地区新闻接口(apiCode 170)官方指南总目录](https://www.showapi.com/guides/region-news-guides-170)