微信小程序 / H5 调用第三方 API 的正确姿势:密钥不出前端,协议留在服务端
小程序和 H5 都不适合直接持有第三方 API 密钥:两端的代码与包都能被使用者获取,正确做法是把密钥与第三方协议留在服务端,前端只调用自己的代理接口;再分别处理小程序域名白名单、H5 的 CORS 与凭证模式,并统一超时、重试与错误通道。涉及具体平台配置项与 API.PLUS 端点细节,本文未联网核验,以官方文档为准。
结论先说:微信小程序和 H5 都不要直接调用需要密钥的第三方 API。前端只调用你自己的服务端接口,第三方密钥、第三方响应结构和重试策略都留在服务端。本文只讨论这个分工带来的具体写法与边界;平台配置项的当前行为请以微信官方文档与浏览器规范为准,本文未联网核验,API.PLUS 的端点与鉴权方式同样待核实。
为什么密钥不能放在前端#
这是一个工程前提,不是待验证的猜测:小程序代码包与 H5 的 JavaScript 都会下发到用户设备,使用者可以获取并阅读其中的字符串常量。一旦密钥写进前端,就等于公开发布。由此可以推出两条做法:
- 前端只持有你自己的会话凭证(可撤销、可限流、可按用户计费),不持有第三方长期密钥;
- 第三方接口的路径、参数拼装、重试与降级都在服务端完成,前端拿到的应是收敛后的业务字段,而不是上游原始响应。
两端的环境差异决定了写法不同#
小程序不是浏览器环境:它没有完整的 DOM / BOM,网络能力由宿主提供(常见为 wx.request),因此不受浏览器同源策略约束,改为受后台配置的请求域名限制,通常要求 HTTPS。H5 则相反,走标准浏览器请求,受同源策略与 CORS 约束。把这两类差异混在一份“通用请求封装”里,是小程序与 H5 共用代码时最常见的坑。
| 维度 | 小程序 | H5 |
|---|---|---|
| 密钥可见性 | 包可被获取,不可放密钥 | JS 可被查看,不可放密钥 |
| 请求限制来源 | 后台配置的请求域名白名单 | 同源策略与 CORS 响应头 |
| 跨域预检 | 不适用浏览器预检语义 | 非简单请求会先发 OPTIONS |
| Cookie | 不依赖浏览器 Cookie 语义 | 需 credentials 与 SameSite 配合 |
白名单的具体配置入口、是否支持子域、是否允许开发期临时关闭校验,均待核实,不要按记忆里的旧行为上线。
服务端代理的最小职责#
代理不是简单的转发。至少要承担四件事:注入密钥、设定超时、把上游错误翻译成自己的错误码、对可能重复提交的写操作带幂等键。下面是一个未执行的示例,仅示意职责边界,不是可运行实现,上游地址与鉴权方式均为占位:
// 未执行示例 · 环境:Node.js 服务端 · 端点与鉴权待核实
app.post('/api/proxy', async (req, res) => {
const ac = new AbortController();
const timer = setTimeout(() => ac.abort(), 8000);
try {
const upstream = await fetch('https://example.com/v1/endpoint', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.PLUS_KEY, // 占位,只存在于服务端
'Content-Type': 'application/json',
'Idempotency-Key': req.get('Idempotency-Key') || ''
},
body: JSON.stringify(req.body),
signal: ac.signal
});
const text = await upstream.text();
res.status(upstream.status).type('application/json').send(text);
} catch (e) {
res.status(502).json({ code: 'UPSTREAM_FAILED', message: '上游不可用' });
} finally {
clearTimeout(timer);
}
});
注意示例里把上游状态码原样透传只是最省事的做法;更稳妥的是区分「可重试」(超时、5xx)和「不可重试」(参数错误、鉴权失败),只对前者做有限次退避重试,且重试必须复用同一个幂等键。
前端该写什么#
- 只认一套错误通道:网络失败、HTTP 非 2xx、业务码失败要归一成同一种结构,避免调用方在三处判断。
- 超时由前端也设一份,略长于服务端超时,防止界面无限等待。
- 不在前端做密钥轮换或签名:这类逻辑一旦下发就失去意义。
- H5 端确认 CORS 细节:自定义请求头(如幂等键)会触发预检,服务端必须正确响应
OPTIONS并声明允许的头;带凭证时通配符*不可用。
边界与未决项#
如果第三方接口本身提供可公开调用的免费额度、且不介意额度被消耗,直连在技术上可行,但计费与限流将无法按用户归因。反之,只要涉及付费额度、私有数据或需要审计,代理就是必须的。API.PLUS 的具体端点、鉴权头格式、限流窗口与计费口径,本文没有可核验材料,请在接入前查阅官方文档并自行验证。