用户登录

技术文章

外部链接将在新标签页打开。

微信小程序与 H5 调用第三方 API:密钥该放哪、请求该走哪条链路

一句话回答

小程序和 H5 都不应直接持有第三方 API 密钥。可维护的做法是前端只请求自有后端,由服务端代理做端点白名单、方法限制、超时与错误归一化;小程序侧还需在小程序管理后台配置 request 合法域名,H5 侧需处理同源策略与 CORS。文中给出未执行的服务端代理与小程序调用骨架,具体平台规则以官方文档为准。

结论先说:小程序和 H5 调用第三方 API 的“正确姿势”不是在页面里写一个 fetch 或 wx.request 就完事,而是把第三方调用收到自己的服务端,前端只与自有域名通信。这样做的原因不是风格问题,而是密钥载体、平台域名规则和浏览器同源策略共同决定的。

先分清两条链路#

小程序与 H5 的约束来源不同,混着写很容易漏项。

维度微信小程序H5 页面
发起方式wx.request 等小程序 APIfetch / XMLHttpRequest
域名限制需在小程序管理后台配置 request 合法域名;按微信官方文档要求,域名须使用 HTTPS,不能使用 IP 或 localhost受同源策略约束,跨域需第三方响应 CORS 头
密钥可见性安装包可被解包,包内字符串可读JS 可在浏览器直接查看

上表关于小程序域名的要求属于常见平台规则,本文未联网核验,具体条款、端口与备案要求请以微信公众平台开发者文档当时版本为准(待核实)。

密钥不进前端,代理只开白名单#

把 AppSecret、第三方 API Key 写进小程序包或 H5 的 JS,等价于公开。可维护的边界是:密钥只存在于服务端环境变量,前端请求路径里只出现业务名,不出现上游地址。

服务端代理需要收窄四件事,否则代理本身会变成新的攻击面:

  • 端点白名单:用固定映射表把内部路径映射到上游路径,不要让客户端传入完整 URL,避免服务端请求伪造(SSRF)。
  • 方法与参数约束:只放行需要的 HTTP 方法;查询参数按键名过滤,避免客户端覆盖签名、分页上限等关键字段。
  • 超时与中断:给上游调用设显式超时,超时后中止请求并向客户端返回可识别的错误码。
  • 响应裁剪:只回传前端需要的字段,避免上游返回的调试信息、内部标识被带到客户端。

服务端代理骨架(未执行的示例)

下面的代码未实际运行,仅用于说明边界位置,不是可直接上线的实现;域名与密钥为占位。

// 未执行的示例:Node.js + Express,仅示意白名单与超时
import express from "express";
const app = express();

const ALLOWED = new Map([
  ["weather", "https://api.example.com/v1/weather"],
]);

app.get("/api/:name", async (req, res) => {
  const target = ALLOWED.get(req.params.name);
  if (!target) return res.status(404).json({ error: "endpoint_not_allowed" });

  const url = new URL(target);
  // 只透传允许的查询参数
  const q = req.query.city;
  if (typeof q === "string") url.searchParams.set("city", q);

  const ac = new AbortController();
  const timer = setTimeout(() => ac.abort(), 5000);
  try {
    const upstream = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.UPSTREAM_KEY}` }, // 密钥仅在服务端
      signal: ac.signal,
    });
    if (!upstream.ok) return res.status(502).json({ error: "upstream_failed" });
    const data = await upstream.json();
    res.json({ city: data.city, temp: data.temp }); // 裁剪字段
  } catch {
    res.status(504).json({ error: "upstream_timeout" });
  } finally {
    clearTimeout(timer);
  }
});

小程序端调用骨架(未执行的示例)

小程序只请求自有域名,并把超时与错误分类写在调用处,避免把上游失败统一显示成“网络异常”。

// 未执行的示例:域名替换为已在小程序后台配置的自有域名
wx.request({
  url: "https://your-domain.example.com/api/weather?city=shanghai",
  timeout: 5000,
  success(res) {
    // 400 参数问题、502 上游失败、504 超时应分别处理
  },
  fail() {
    // 网络不可达、域名未配置等
  },
});

上线前的核对清单#

  1. 小程序后台的 request 合法域名是否已包含生产域名,证书是否有效且链完整(证书细节待核实)。
  2. H5 是否只调用自有域名;若确有直连第三方需求,第三方是否对目标源返回 CORS 头、是否支持凭证模式。
  3. 代理层是否做了端点白名单、参数过滤、超时与并发限制。
  4. 日志是否脱敏:请求头中的 Authorization、查询串中的签名参数不应落盘明文。
  5. 密钥是否可轮换,轮换窗口内旧密钥是否可控地失效。
  6. 错误码是否能区分“客户端参数错”“上游错”“超时”,便于前端展示与告警分级。

剩余的不确定项#

本文没有联网核验,也未在真机或浏览器中实际运行上述代码。以下信息需要你按当前版本自行确认:小程序的域名配置规则与数量上限、wx.request 的默认超时与可配置范围、H5 直连场景下第三方的 CORS 策略、以及所选用第三方 API 的鉴权方式与配额口径。这些都属于会随版本变化的平台约束,宜以官方文档与实测记录为准。

作者:沐小悠

本文约 7 分钟读完 · 关键词:微信小程序、H5、第三方 API、服务端代理、密钥安全

更多文章 GET 示例接口

「」标签下的其他文章