今日油价:车主服务 APP 如何集成?从加油页到实时油价卡片的全链路设计
# 今日油价:车主服务 APP 如何集成?从加油页到实时油价卡片的全链路设计
> 接口/接入点:今日油价 · 查询油价(138-46) · 免费 · POST/GET · JSON · 适用人群:全栈工程师、车主产品开发者 · 阅读时间:约 8 分钟
## TL;DR
- 典型链路:用户选省份 → 后端调今日油价(prov=省名)→ 缓存每日结果 → 前端加油页渲染油价卡片。
- 关键工程点:**缓存**(免费接口也有档位限制)、**定时刷新**(每日 7 点更新)、**省份选择组件**。
- 本文给出后端调用 + 前端卡片的落地代码骨架。
## Why
车主 APP 的加油页、汽车公众号的菜单、养车小程序的首页,都可以挂一个「今日油价」卡片。用户加油前看一眼常去省份的 92/95 价格,体验立刻不一样。今日油价免费、覆盖全国 31 省、每日 7 点更新,非常适合做常驻卡片。
## What
| 项 | 说明 |
|----|------|
| 接入点 | 查询油价(138-46) |
| 请求参数 | `prov`(省名,选填;建议传省名查单省) |
| 返回 | `list[0]`:单省各标号价格 |
| 计费 | 免费,有使用档位限制 |
| 更新频率 | 每日 7 点 |
## How
**步骤 1:前端省份选择**
用省份下拉/标签让用户选省份,默认值取用户定位或上次选择。
**步骤 2:后端代理调用(避免 AppKey 暴露)**
AppKey 必须放服务端,前端只调你自己的接口。
```python
import requests, json
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/api/oil-price")
def oil_price():
prov = request.args.get("prov", "北京")
resp = requests.post(
"https://route.showapi.com/138-46",
data={"appKey": "YOUR_APPKEY", "prov": prov},
timeout=10,
).json()
body = resp.get("showapi_res_body", {})
if body.get("ret_code") != 0:
return jsonify({"ok": False, "msg": "查询失败"}), 502
item = body["list"][0]
return jsonify({
"prov": item["prov"],
"p92": float(item["p92"]) if item["p92"] else None,
"p95": float(item["p95"]) if item["p95"] else None,
"p98": float(item["p98"]) if item["p98"] else None,
"p0": float(item["p0"]) if item["p0"] else None,
"ct": item["ct"],
})
```
cURL(服务端验证):
```bash
curl -X POST "https://route.showapi.com/138-46?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" \
-d "prov=%E5%8C%97%E4%BA%AC"
```
**步骤 3:前端渲染卡片**
```html
<div class="oil-card" id="oilCard">加载中…</div>
<script>
async function loadOil(prov) {
const r = await fetch(`/api/oil-price?prov=${encodeURIComponent(prov)}`);
const d = await r.json();
if (!d.ok && d.prov === undefined) { document.getElementById('oilCard').textContent = '暂不可用'; return; }
document.getElementById('oilCard').innerHTML =
`<h3>${d.prov} 今日油价</h3>
<p>92号:${d.p92 ?? '—'} 元/升</p>
<p>95号:${d.p95 ?? '—'} 元/升</p>
<p>0号柴油:${d.p0 ?? '—'} 元/升</p>
<small>更新于 ${d.ct}</small>`;
}
loadOil('北京');
</script>
```
## 返回示例与解析
后端拿到 `list[0]` 后,把字符串价格转成数字再下发前端,前端用 `?? '—'` 处理空值(部分标号该省无数据)。
## 进阶/边界
- **务必缓存**:免费接口有档位限制,每个用户每次进页都打实时请求会很快超限。建议按 `prov` 缓存,TTL 对齐每日 7 点更新(见[《今日油价:免费也有档次限制,如何设计缓存避免超限?》](https://www.showapi.com/guides/oilprice-cache-138))。
- **AppKey 别放前端**:放服务端代理,避免泄露。
- **空值处理**:历史标号(90/93/97)部分省份为空,前端显示「—」。
## FAQ
**Q:AppKey 能放前端吗?**
A:不能。AppKey 应仅存在于服务端,前端调你自己的后端接口,由后端代理请求今日油价。
**Q:每个用户进页面都实时查一次会怎样?**
A:免费接口有档位限制,高频实时查容易超限。按省份做服务端缓存即可。
**Q:价格要转数字吗?**
A:接口返回的是字符串,前端展示可直接用,但做排序/对比需先转数字,空字符串请判空。
## 相关能力 / 下一步阅读
- [今日油价:免费也有档次限制,如何设计缓存避免超限?](https://www.showapi.com/guides/oilprice-cache-138)
- [今日油价:公众号/小程序油价查询方案,菜单触发+省份选择+卡片展示](https://www.showapi.com/guides/oilprice-wechat-miniapp-138)
- **本系列共 13 篇**:查看[今日油价开发指南总目录](https://www.showapi.com/guides/oilprice-guides-138)