微信小程序快递查询:密钥必须放服务端
2026-07-26 · 阅读约 6 分钟
在微信小程序里做「物流查询」页面很常见,但很多人第一版就踩同一个坑:直接在 wx.request 里拼上快递 API 的密钥。
这一步等于把密钥公开了。本文讲清楚为什么不能这么做,以及正确的两种代理架构——微信云函数 与
自建服务器,各配一份可直接用的示例。
一、错误做法:在 wx.request 里直接调用快递 API
小程序的前端代码会随安装包下发到用户手机,可以被反编译,网络请求也能被抓包。任何写死在前端的东西——包括密钥——都视同公开。 下面这种写法千万别用:
// ❌ 错误示范:绝对不要这样写
// Secret Key 会随小程序包一起下发到手机,抓包或反编译即可读到
wx.request({
url: 'https://api.kuaidichaxunapi.com/v1/tracking/trace',
method: 'POST',
header: {
'Authorization': 'Bearer pk_xxx:sk_xxx', // 密钥暴露!
'content-type': 'application/json',
},
data: { items: [{ courierCode: 'cainiao', trackingNumber: 'CGD0000123456' }] },
});
这样写有两个致命问题:一是 Secret Key 泄露,别人能拿你的额度刷到爆;
二是你还得把 api.kuaidichaxunapi.com 加进小程序的 request 合法域名,等于把调用入口也摆到明处。
二、正确架构:小程序 → 代理 → 快递 API
解决办法是加一层「代理」:小程序只跟你自己的代理说话,代理在服务端保管密钥、再去请求快递 API, 密钥永远不进入小程序包。代理有两种常见实现——微信云开发的云函数,或你自己的服务器。
三、方案 A:微信云函数
如果项目用了微信云开发,这是最省事的方案。密钥配置在云函数的环境变量里,云函数内部去请求快递 API:
// cloudfunctions/kuaidi/index.js —— 微信云开发云函数
// 密钥配置在云函数「环境变量」里,不写进小程序前端
const AUTH = 'Bearer ' + process.env.KUAIDI_PK + ':' + process.env.KUAIDI_SK;
// 云函数运行时需 Node 18+ 才有全局 fetch;更低版本请改用 axios
exports.main = async (event) => {
const items = (event.items || []).slice(0, 10);
const res = await fetch('https://api.kuaidichaxunapi.com/v1/tracking/trace', {
method: 'POST',
headers: { 'Authorization': AUTH, 'Content-Type': 'application/json' },
body: JSON.stringify({ items }),
});
const json = await res.json();
return json.data; // 只回传 results / summary
};
小程序端用 wx.cloud.callFunction 调用,走的是微信内部通道,
不占用 request 合法域名,也就省去了域名配置:
// pages/chaxun/chaxun.js —— 调用云函数,走微信内部通道
// 无需在 request 合法域名里配置任何地址
wx.cloud.callFunction({
name: 'kuaidi',
data: { items: [{ courierCode: 'cainiao', trackingNumber: 'CGD0000123456' }] },
success(res) {
const r = res.result.results[0];
if (r.success) {
console.log(r.data.deliveryStatusText); // 例如「运输中」
} else {
console.warn(r.error.code);
}
},
}); 四、方案 B:自建服务器
如果你已经有后端(要多端复用,或不想用云开发),就让小程序请求自己的服务器,服务器再转发。 服务端代码与 Node.js 篇 的 Express 代理完全一样,小程序端这样写:
// 方案 B:小程序请求「你自己的服务器」,而不是快递 API
wx.request({
url: 'https://your-server.com/api/kuaidi', // 要加入 request 合法域名的是这个域名
method: 'POST',
header: { 'content-type': 'application/json' },
data: { items: [{ courierCode: 'cainiao', trackingNumber: 'CGD0000123456' }] },
success(res) {
const r = (res.data.results || [])[0];
if (r) console.log(r.success ? r.data.deliveryStatusText : r.error.code);
},
});
这里有个最容易搞错的点,单独强调:需要加入 request 合法域名的,是你自己服务器的域名
(https://your-server.com),不是 api.kuaidichaxunapi.com——
因为小程序端根本不直接访问快递 API。配置路径是「小程序管理后台 → 开发管理 → 开发设置 → 服务器域名 → request 合法域名」,
且该域名必须是 HTTPS、已完成 ICP 备案。
五、两种方案怎么选
| 对比项 | 方案 A:云函数 | 方案 B:自建服务器 |
|---|---|---|
| 密钥存放 | 云函数环境变量 | 服务器环境变量 |
| request 合法域名 | 无需配置(走微信通道) | 需加入你的服务器域名 |
| 是否需要服务器 | 否,按调用计费 | 是,自行部署维护 |
| 适合场景 | 纯小程序、快速上线 | 已有后端、多端复用 |
六、展示结果
两种方案拿到的都是同一份 data(含 results / summary)。展示时关注这几个字段:
deliveryStatusText:可直接显示的中文状态(如「运输中」「已签收」);isDelivered:布尔值,做「待收货 / 已完成」分类时直接用它;progresses:轨迹数组,最新在前,每条含dateTime、location、status、description。
完整字段与错误码见接口文档;Node 服务端代理的写法见 用 Node.js 对接快递查询接口;支持的快递公司见快递公司页。 还没有密钥就先注册(邮箱即可,无需企业认证)。