微信小程序与 H5 调用第三方 API:白名单、CORS 与代理链路的正确顺序
一句话回答
小程序和 H5 调用第三方 API 的正确做法是先确认两条运行时各自的约束:小程序侧受 request 合法域名限制,H5 侧受同源策略与 CORS 预检限制;两者都应经过自有后端或边缘函数转发,避免把长期密钥放到前端。文章给出代理链路、两端的最小代码骨架(未执行示例)和排查顺序,并标注了本次材料无法核实的部分。
先给结论:让小程序或 H5 直接携带密钥去调用第三方 API,属于错误的接入方式。合理的做法是把调用链路改成「前端 → 自有后端或边缘函数 → 第三方 API」,前端只持有短期凭证,不持有长期密钥;同时分别处理小程序的域名白名单和浏览器的跨域规则。这两类约束来自运行环境,与具体调用哪家 API 无关。
1. 两条运行时的约束不同#
| 维度 | 微信小程序 | H5(浏览器) |
|---|---|---|
| 请求发起方 | wx.request 等平台 API | fetch / XMLHttpRequest |
| 域名限制 | 需在小程序管理后台配置为 request 合法域名,且仅支持 HTTPS | 受同源策略约束,跨域需服务端返回 CORS 响应头 |
| 预检请求 | 不适用浏览器 OPTIONS 语义 | 非简单请求会先发 OPTIONS 预检 |
| 密钥可见性 | 打包产物可被解包查看 | 源码与网络面板均可查看 |
小程序后台对合法域名的数量上限、审核时延等细节,以微信官方文档为准;本次材料未提供,待核实。
2. 推荐的调用链路#
- 前端调用自有域名的接口,例如
https://api.example.com/proxy/...(占位域名)。 - 自有后端保存第三方密钥,负责签名、限流、缓存和错误码归一。
- 后端再向 API.PLUS 发起真实请求。API.PLUS 的具体路径、鉴权头名称、配额与计费规则,本次材料未提供,需按官方接口契约核对后再写死。
这样做还有一个附带好处:第三方的超时、限流和字段变更可以在一处吸收,前端不必跟着改版。
3. 小程序侧的最小骨架#
// 未执行的示例,仅示意调用自有代理,请求头中不含第三方密钥
wx.request({
url: 'https://api.example.com/proxy/demo', // 占位路径
method: 'GET',
timeout: 8000,
success(res) {
// 先判状态码再解析业务字段,字段名以实际契约为准
},
fail(err) {
// 网络层失败与 4xx/5xx 分开处理,便于定位是域名、证书还是业务问题
}
});
上线前需确认该域名已经加入 request 合法域名,且证书链完整;域名改动后要重新发布小程序才会生效。
4. H5 侧的最小骨架#
// 未执行的示例
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 8000);
const res = await fetch('https://api.example.com/proxy/demo', { // 占位路径
method: 'GET',
headers: { 'Accept': 'application/json' },
credentials: 'omit',
signal: controller.signal
});
clearTimeout(timer);
如果代理接口带自定义请求头(如 Authorization),浏览器会先发 OPTIONS 预检,服务端需要正确响应 Access-Control-Allow-Origin、Access-Control-Allow-Headers 等头,否则请求在发出前就被拦截。
5. 排查顺序#
- 请求有没有离开客户端?小程序看是否报域名不合法,H5 看 Network 面板是否有 OPTIONS 记录。
- 预检或白名单通过后,再看状态码:401/403 通常是鉴权,429 是限流,5xx 是上游。
- 状态码正常但数据不对,才去看字段契约和编码。
证书、域名白名单、CORS 这类问题在本地开发环境往往看不到,必须在真机或线上域名验证。
6. 本次未能确认的部分#
实测性能、并发上限与具体排障数字均无测试记录,本文不做断言;API.PLUS 的接口定义与最新平台规则请以其官方文档为准。