ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微信小程序API调用实战:从wx.request到登录态与请求封装

微信小程序API调用实战:从wx.request到登录态与请求封装 微信小程序开发里最容易被新手当成“黑魔法”的就是 API 调用。我见过很多朋友页面写得挺漂亮一到对接接口就卡住最常见的台词是“我这请求明明发了为什么后端没收到”或者“后端返回了小程序里怎么读不到”。折腾半天才发现不是代码跑不通而是对微信小程序 API 的调用规则理解有偏差。这篇文章不是我临时整理的概念汇总而是我实际做过多个微信小程序项目之后按完整流程沉淀下来的一套 API 调用思路。从 wx.request 的基础用法、域名配置、登录态与 code 换 token到返回结构设计、常见报错排查和请求封装基本覆盖了日常开发里 90% 的网络请求场景。适合刚接触小程序开发的新手也适合后端同学快速理解小程序端请求的约束。1. 小程序 API 到底是什么先分清两类接口1.1 微信能力接口和业务接口不是一回事我把小程序开发里说的“API”拆成两类。一类是微信官方提供的能力接口比如 wx.request、wx.login、wx.getStorage、wx.chooseImage这类接口是基础库自带的你调用它是在和微信客户端打交道。另一类是你自己后端或者第三方平台提供的业务接口比如获取商品列表、提交订单、识别图片、调用大模型这类接口要通过 wx.request 或 wx.cloud.callFunction 这类网络通道来触达。为什么要分清这两类因为很多刚上手的人会犯一个错误以为所有接口都要在小程序后台配置域名。实际上微信官方接口比如 wx.login、wx.getUserProfile不需要你配置任何 request 合法域名它们是基础库直接封装好的能力。但你自己的业务接口只要不是云开发就必须在小程序后台把域名加进白名单否则请求大概率直接 fail。另外还需要知道这两类接口的调用风格也不完全一样。业务接口是我们自己后端说了算字段怎么传、错误码怎么定、超时多久都可以商量。微信官方接口则必须按微信的规则来比如 wx.login 里拿到的是临时 code不是用户身份很多新手在这里理解偏差导致后面登录逻辑怎么写都不对。1.2 同步异步、回调与 Promise调用方式的演变微信小程序很多 API 都是异步的因为你要等待微信客户端或者服务器响应不可能阻塞页面。刚开始的小程序基础库几乎所有的异步 API 都是回调风格也就是 success、fail、complete 三个回调。后来基础库版本升级也支持在部分 API 上使用 Promise 风格记得我先看一下当前基础库版本。举一个最常见的例子保存数据到本地缓存// 回调写法 wx.setStorage({ key: token, data: abc123, success() { console.log(保存成功); }, fail() { console.log(保存失败); } });同样的功能用同步 API 更直接// 同步写法 try { wx.setStorageSync(token, abc123); } catch (e) { console.error(保存失败, e); }很多人在用 wx.request 的时候也纠结它其实同时支持回调风格但官方并没有默认返回 Promise需要自己封装一层。后面我在第四章会专门讲怎么封装出好用的请求方法。在这里先记住一个原则看清你用的 API 是同步还是异步是否支持 Promise别把回调函数当同步代码用这是排查“为什么 res 是 undefined”的核心原因。2. 环境与配置请求发不出去的常见鬼门关2.1 AppID、项目创建和基础库版本开发小程序第一步不是写代码而是把环境整明白。用测试号可以体验大部分能力但真正做项目建议注册一个小程序账号拿到 AppID。因为很多 API 能力在测试号里是受限的比如部分开放接口、云开发、订阅消息等你在没 AppID 的情况下开发遇到“这个接口怎么没反应”的问题会特别多。创建项目的时候开发工具会让你选后端服务我一般建议选“不使用云服务”这样更贴近传统的 API 对接方式。如果你想要免域名备案、免运维再考虑云开发。另外基础库版本这点很容易被忽略。你本地开发工具默认基础库可能是最新的但用户手机上不一定。如果你的页面用到了某个较新的 API而用户的基础库版本过低调用就会静默失败或者直接报错。开发者工具右上角可以切换基础库版本我习惯在兼容性列表里确认一下当前 API 的最低基础库要求。2.2 request 合法域名开发环境可以暂时绕过但别养成习惯这一节是小程序 API 调用里最容易被卡住的地方。你的后端接口如果是 HTTP 的比如 http://localhost:8080 或者 http://192.168.1.100:8080在小程序里直接 wx.request 大概率会报错。原因是小程序要求 request 请求的域名必须是 HTTPS并且需要在小程序管理后台配置 request 合法域名。开发阶段开发者工具提供了一个跳过校验的开关。打开开发者工具在“详情-本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”这样你本地跑 HTTP 接口就不会被拦截。这个开关只影响开发者工具和真机调试模式不影响线上版本。但我要给个提醒别因为勾了这个开关就一直用 HTTP 接口开发。发布前一定把正式环境切到 HTTPS并且把域名加到小程序后台白名单里。否则会出现“我本地测得好好的一上线怎么全部请求失败”这种尴尬情况。而且真实用户手机上访问请求即使你后台配置了域名也必须是备案过的 HTTPS 域名证书链不完整也会导致请求失败。2.3 域名白名单配置的细节不是配了立刻生效在小程序后台配置 request 合法域名的时候要注意几个细节。一是域名不要加 http:// 或 https:// 前缀直接填域名二是不要带路径三是如果需要多个环境比如测试环境和生产环境建议把域名都加上但开发时通过代码切换别让请求满天飞。还有配置域名后不是马上生效偶尔会有几秒到几分钟的延迟如果刚配置完立刻测试可能还是报 url not in domain list。碰到这种问题我的排查顺序一般是先看我当前有没有勾选“不校验合法域名”再看后台域名是否正确配置最后确认后端服务是否真的启动、手机和电脑是否在同一个局域网。千万别一上来就怀疑微信的缓存大概率是你自己的配置没搞对。3. 核心基础wx.request 从原理解析到顺手封装3.1 GET 请求入门必写的第一个请求wx.request 是小程序里发 HTTP 请求的核心 API没有它你基本没法对接自己后端。先看一个最简单的 GET 请求拉取一篇文章详情wx.request({ url: https://api.example.com/article/10086, method: GET, header: { Content-Type: application/json }, success(res) { console.log(请求成功, res.data); }, fail(err) { console.error(请求失败, err.errMsg); } });这里 url 是接口地址method 默认是 GET不传也可以但建议显式写一下。success 回调里拿到的 res 是完整的响应对象包括 statusCode、header、data 等真正业务数据一般都在 res.data 里这个别弄混了。很多新手把 res 当成 res.data 直接用结果打印出来一堆 statusCode 和 header然后一脸懵。3.2 POST 请求与请求头的正确姿势POST 请求用于提交数据比如登录、提交订单、上传内容。除了 url 和 method最重要是 data 格式和 header 里的 Content-Type。常见的是 JSON 格式wx.request({ url: https://api.example.com/user/login, method: POST, data: { username: zhangsan, password: 123456 }, header: { Content-Type: application/json }, success(res) { if (res.statusCode 200) { console.log(登录成功, res.data); } else { console.error(服务端返回异常, res.statusCode, res.data); } } });这里有个容易踩的小坑如果 header 里的 Content-Type 是 application/x-www-form-urlencoded后端一般按表单格式解析data 里传对象也可以但部分后端框架需要你先把对象拼成查询字符串。与其和不同后端打架我建议后端同学统一接收 JSON前端统一用 application/json格式清晰调试也方便。如果后端硬是要 form 格式你可以用 URLSearchParams 或者自己拼字符串但这类接口往往维护成本高能改就改。3.3 超时时间、statusCode 与缓存处理wx.request 默认超时时间是 60 秒实际开发中我建议显式设置 timeout比如 10 秒或者 15 秒避免用户一直傻等。超时回调在 fail 里errMsg 类似 request:fail timeout。对于响应状态码不要只判断成功还是失败。我习惯把请求处理分成三层第一层是网络层fail 回调说明请求根本没到达服务器或者服务器没正常返回可能是域名问题、断网、超时第二层是 HTTP 状态码res.statusCode 是 2xx 说明 HTTP 层面通了但业务可能还是错的第三层是业务状态码这个在后端返回的数据结构里比如 code 字段。分层判断定位问题会快很多。另外如果你的接口暴露了较新的资源后端可以用 Cache-Control 控制缓存小程序端的 wx.request 默认也会遵循 HTTP 缓存。但如果你不希望某些接口被缓存可以在后端或者请求里加一个时间戳之类的参数这样调试时也能避免被旧数据误导。3.4 把 wx.request 封装成 Promise 风格我早期写小程序的时候每个页面里都写一坨 wx.request结果到处都是重复代码。后来我统一封装了一个 request.js所有页面都从里面导方法。这样做的优势是可以统一处理 baseURL、token、错误提示、登录过期跳转后续维护只需要改一个文件。下面是一版简化的封装核心代码const BASE_URL https://api.example.com/v1; function request(path, method, data, options {}) { const token wx.getStorageSync(token); return new Promise((resolve, reject) { wx.request({ url: ${BASE_URL}${path}, method: method || GET, data: data || {}, timeout: options.timeout || 15000, header: { Content-Type: application/json, Authorization: token ? Bearer ${token} : }, success(res) { if (res.statusCode 200 res.statusCode 300) { resolve(res.data); } else if (res.statusCode 401) { // 登录失效统一处理 wx.removeStorageSync(token); reject({ code: 401, message: 登录已过期, data: res.data }); } else { reject({ code: res.statusCode, message: HTTP错误${res.statusCode}, data: res.data }); } }, fail(err) { reject({ code: -1, message: err.errMsg || 网络请求失败 }); } }); }); } module.exports { get: (url, data, options) request(url, GET, data, options), post: (url, data, options) request(url, POST, data, options), put: (url, data, options) request(url, PUT, data, options), delete: (url, data, options) request(url, DELETE, data, options) };使用的时候配合 async/await 会非常优雅const { get, post } require(../../utils/request); async function loadDetail() { try { const article await get(/article/10086); this.setData({ article }); } catch (e) { wx.showToast({ title: e.message || 加载失败, icon: none }); } }这里有几个细节需要解释。为什么把 statusCode 判断放在 success 里而不是 fail 里因为微信的规则里只要服务器正常返回了 HTTP 响应哪怕状态码是 500也会走 success 回调。如果你想统一按 Promise 处理就必须在 success 里判断 statusCode把错误信息 reject 出去。其次是统一处理 401一旦接口返回登录态过期前端不用每个页面都写跳登录逻辑封装层直接清 token并让调用方 catch 到错误后再决定怎么跳转。4. 登录态与 Tokencode 换 token 的完整流程4.1 wx.login 拿到的 code 是什么能做什么微信小程序里做用户登录绕不开 wx.login。这个方法会向微信服务器请求一个临时登录凭证 code有效时间大概是 5 分钟且只能用一次。很多新手误以为 code 可以直接当用户身份拿过来就往后端存这是大忌。code 本身没有任何用户信息它更像一张“兑换券”需要小程序后端拿这张券去微信的接口换取 openid、unionid 和 session_key。代码很简单wx.login({ success(res) { if (res.code) { // 把 code 传到后端 console.log(临时code, res.code); } else { console.error(获取code失败, res.errMsg); } } });这个 code 传输过程一般放在“静默登录”阶段。也就是说用户进入小程序后你先不弹任何授权框先悄悄调 wx.login拿到 code 发给后端后端换取 openid 后生成自己体系的 token 返回给小程序。这个 token 才是你后续请求需要携带的身份凭证。4.2 后端用 code 换 session_key 的正确路径后端收到前端传来的 code 后需要调用微信的接口也就是 auth.code2Session用自己的 AppID 和 AppSecret 换取 openid 和 session_key。这里要特别强调AppSecret 绝对不能下发到小程序前端它只能保存在后端服务器。如果你的项目里有人在客户端代码里写了 AppSecret赶紧改掉这等同于把用户数据的大门敞开。后端换取方式一般是后端发一个请求到微信服务器结构大致是GET https://api.weixin.qq.com/sns/jscode2session?appidAPPIDsecretSECRETjs_codeCODEgrant_typeauthorization_code返回内容大致包含 openid、session_key 和 unionid如果有绑定开放平台。拿到 openid 后后端需要做的是查数据库里是否已有这个 openid没有就创建新用户用自己的规则签发一个登录凭证 token比如 JWT附带用户 id 和过期时间把 token 返回给小程序端。为什么要自建 token而不是直接把 session_key 给前端因为 session_key 是微信侧的会话密钥前端拿到它不仅没意义还可能泄露安全信息。自建 token 也方便你控制登录有效期、踢人、刷新等逻辑。4.3 token 存在哪里Storage 还是 globalData小程序端的 token 保存位置我见过不少人纠结。globalData 适合放运行时会经常变的全局状态比如当前用户信息、主题色但小程序一旦退出globalData 会全部清空。token 这种需要跨页面、跨启动保持的数据必须存到 Storage 里也就是 wx.setStorageSync。// 登录成功保存 token wx.setStorageSync(token, token); wx.setStorageSync(userInfo, userInfo); // 其他请求时读取 const token wx.getStorageSync(token);同时我建议在 App.onLaunch 里做一次初始化把 storage 里的 token 读到一个全局变量里方便后续快速判断登录态。但读取用户信息的时候要注意storage 里的数据是本地数据用户可能很久没重新拉取所以每次启动小程序最好重新调一次自己的用户信息接口保证展示的数据是最新的。4.4 请求拦截器自动附加 token有了 token 之后所有需要身份验证的业务接口都应该在请求头上携带它。我常用的做法是在请求封装层统一加上 Authorization 头。后端用 Spring Boot 或者其他框架解析这个头就能知道当前用户是谁不需要每个接口自己传 userId安全性和可维护性都好很多。例如上一节封装代码里已经有Authorization: token ? Bearer ${token} : 这里用 Bearer 开头是习惯用法后端解析时只需要移除前缀然后把 token 拿来校验。如果想要更简单的自定义 header比如 X-Token也没问题但团队协作时最好统一规范。我在项目里一般会前后端约定一个名称避免出现前端传了 token后端读的是另一个字段名然后来回扯皮。另外登录接口本身不需要带 token因为那时还没有 token。如果封装层里统一加可能会带一个空字符串后端如果严格要求看到 Authorization 头可能会解析空字符串导致问题。所以好一点的封装应该支持配置是否需要带 token比如 options.auth false 就不加。4.5 登录态过期与静默刷新token 总会过期。最粗放的做法是用户发现功能不可用才提示重新登录体验很差。我一般会把 token 过期和接口错误处理联动起来。后端返回 401 时前端封装层统一触发静默刷新流程清除旧的 token调用 wx.login 获取新的 code把 code 发给后端换一个新的 token用新 token 重新发起刚才失败的请求。这个过程用户完全无感知。不过静默刷新要考虑并发问题如果页面上同时发出 5 个请求每个都发现 401就会触发 5 次重复登录。我目前的处理方式是维护一个 isRefreshing 标志和一个 promise 队列只让第一个请求去刷新 token其他请求等待同一个刷新 Promise 完成然后共享新的 token 重新调用。let isRefreshing false; let refreshPromise null; function refreshToken() { if (refreshPromise) { return refreshPromise; } refreshPromise new Promise((resolve, reject) { wx.login({ success(res) { post(/user/silent-login, { code: res.code }, { auth: false }) .then((data) { wx.setStorageSync(token, data.token); resolve(data.token); }) .catch(reject) .finally(() { refreshPromise null; }); }, fail: reject }); }); return refreshPromise; }这段代码在一个真实项目里效果很明显。用户挂着小程序超过 token 有效期再点任何按钮都会有一个短暂的刷新过程但不会看到登录页反复跳转。唯一要注意的是静默登录接口本身也要在封装层里跳过“自动重试”逻辑避免循环调用。5. 返回数据与错误处理很多报错其实在参数结构上5.1 统一后端返回结构少一点例外少一点崩溃我在对接第三方 API 的时候最痛苦的事是每个接口返回格式不一样。有些直接返回数组有些是对象有些错误时返回一个字符串。这在小程序端写起来极其痛苦。如果是自研接口我强烈建议后端所有接口统一返回结构类似{ code: 0, message: success, data: { ... } }code 为 0 表示成功非 0 表示业务异常message 用于前端做提示data 装业务数据。这种格式有几个好处前端封装层可以统一判断 code错误提示可以直接取 message后端也可以把异常堆栈藏在日志里不暴露给用户。有一种情况需要灵活处理就是文件上传或者第三方回调接口返回格式可能不是 JSON。比如 wx.uploadFile 的返回数据有时后端返回的是字符串你需要先 JSON.parse 再读取。这个我在实际项目里也踩过明明后端返回了 JSON但小程序里打印出来是一串字符串原来是微信把 body 里的内容原样透传了需要自己解析。5.2 参数格式对齐400 invalid schema 的排查思路结合最近很多人在对接大模型 API 时看到的报错api error: 400 invalid schema for function artifact这类问题其实和微信小程序本身关系不大但小程序作为前端也一样会遇到因为你把参数传给后端后端可能进一步转发给第三方服务。所谓 invalid schema意思是你的请求参数不符合服务端定义的 JSON Schema常见的原因有字段名写错多一个 s 少一个 s字段类型不对接口要 string你传了 number嵌套结构不对比如接口期望的是一个数组你传了对象枚举值不在允许范围内多传了额外字段部分严格校验的后端会直接报错。排查这类 400 错误我一般这么做先把请求参数原样打印出来缩进格式化后和服务端文档里给出的示例一行一行对比重点检查字段名和类型。不要用 console.log 打印到一个很长的对象里否则很容易看花眼更好的办法是 JSON.stringify 之后格式化到一个小程序弹窗或者复制到编辑器里对比。如果前端参数看起来没问题再去查后端是不是做了一层字段映射把参数改了名字。说实话这种问题 90% 都是前后端对“字段命名”没对齐真正是第三方服务拒绝的不多。所以团队合作时接口文档一定要维护好最好在文档里带上“示例请求体”和“所有字段类型”省得大家靠猜。5.3 防御性取数不要动不动 res.data.data小程序端经常遇到接口返回嵌套很深的数据比如 res.data.data.list。我理解因为 request 封装层已经返回了 res.data如果后端统一结构里 data 又包一层调用方就是 data.data。这个写多了确实容易乱尤其当 data 为空或字段名变了的时候一不小心就 undefined。我现在的习惯是封装层返回完整 body然后在页面或者接口模块层面对返回体做一次前置解析。比如function parseResponse(res) { if (res res.code 0) { return res.data; } throw new Error((res res.message) || 业务异常); }这样页面拿到的就是纯业务数据不会再出现 data.data.data 这种地狱写法。如果后端某个接口没有按统一结构返回就在该接口的模块里单独处理不要让页面代码去兼容各种格式。另外取数时尽量用可选的保护方式比如const list articleData?.list ?? [];或者在小程序基础库足够新时也可以用逻辑或兜底。这样即使后端某天少返回一个字段前端也不会整个页面白屏。5.4 编码与特殊字符中文、emoji、URL 参数小程序请求里如果携带中文参数建议对 URL 参数做一次 encodeURIComponent 编码避免出现乱码。比如搜索关键词用户输入“你好”拼到 URL 时直接用可能出错尤其当后端用的是旧框架时。我一般在拼接请求路径时统一做function encodeParams(params) { return Object.keys(params) .map((key) ${encodeURIComponent(key)}${encodeURIComponent(params[key])}) .join(); }对于 data 里的 JSON 内容wx.request 会自动帮你序列化一般不需要手动 encode。但如果你直接在 url 里拼接了一个 JSON 字符串就必须编码。还有如果用户输入了 emoji 字符有些后端存储用的字符集不支持 4 字节 utf8会报错这时候多半是后端数据库的问题前端只能尽量在提交时做校验比如某些输入框限制 emoji 输入或者后端改用 utf8mb4。6. 调试与排查看懂报错不靠瞎猜6.1 开发者工具 Network 面板是最直观的起点调试小程序 API第一件事是看开发者工具的 Network 面板。在工具里点击“Network”标签能看到所有请求的列表点开任意一个能看到请求 URL、请求头、响应状态码、响应体。新手容易犯的错是不看这个面板直接看 console 里报的 undefined然后瞎改代码。如果你的请求没有出现在 Network 面板里说明请求压根没发出去大概率是域名没在白名单、小程序开发工具没开“不校验合法域名”开关或者代码里某个条件没满足根本没调用到 wx.request。如果请求出现了但是状态码是 400、500那问题就不在前端网络层而在后端逻辑或者参数结构。用 Network 面板先把“前端是否发请求”和“后端是否返回了错误响应”区分开能省下大量排查时间。6.2 真机调试里的 vConsole手机上看接口开发者工具模拟器毕竟不是真实环境有时候电脑上正常手机上报错。特别是涉及到用户授权、手机网络环境、HTTPS 证书之类的必须在真机上测。真机调试其实很简单在开发者工具点“真机调试”生成二维码手机扫码后手机上的小程序会进入调试模式同时开发者工具里能看到 console 日志和网络请求。如果扫码调试时不想开电脑也可以在小程序代码里引入 vConsole 的 npm 包或者使用小程序的“调试”功能在手机右上角菜单里打开调试模式页面底部就会悬浮一个 vConsole 按钮。点开它能看到 console 日志和请求信息适合在手机上直接自查问题。不过发布到生产环境时记得把 vConsole 关掉避免调试信息暴露给用户。6.3 一次真实问题排查从 Network 到后端日志我说一个自己遇到过的问题帮你也建立一个排查思路。当时小程序里有一个接口用户在真机上偶尔点击没反应电脑上复现不了。我打开 Network 面板发现请求发出了但 statusCode 是 504。这就是一个异常状态说明后端已经收到请求但是响应超时了。然后再去看后端日志发现这个接口内部调用了一个外部服务那个服务偶尔会非常慢导致整体超时。如果我没有先看 Network 面板而是去看前端代码可能又会怀疑 token 没带、参数有问题转一大圈才发现是后端依赖的外部服务慢。所以我的经验是先确认请求发出去了再确认响应状态码再确认后端日志有没有记录最后才回来改自己的代码。顺序反了排查效率极低。6.4 常见报错速查表碰到问题先翻表我在维护项目时整理过一份报错速查表分享出来给你参考报错信息或现象可能原因处理方式url not in domain list域名未在小程序后台配置配置 request 合法域名或开发时勾选“不校验合法域名”request:fail timeout后端处理太慢或网络超时调大 timeout后端优化接口耗时statusCode 200 但业务异常后端返回结构里 code ! 0按后端业务错误码处理提示 message400 invalid schema ...参数不符合接口定义的 JSON Schema逐字段比对文档检查类型、枚举值、嵌套结构401 Unauthorizedtoken 缺失或过期清理 token重新登录或用 refresh_token 刷新500 Internal Server Error后端代码异常看后端日志别在前端反复重试component ... does not have a method组件里调用了一个不存在的方法检查组件 methods 定义以及页面方法名是否写错handshake failed due to invalid upgrade headerWebSocket 或普通请求握手异常检查代理环境、本地网络、HTTPS 证书链是否完整failed to connect to docker api at npipe...本地开发环境 Docker 未启动启动 Docker 服务检查本地服务依赖这只是常见问题的一部分。你在项目里遇到的报错千奇百怪但核心原则是不要慌。先看是哪一层报的错小程序层、网络层、还是后端层。逐层筛查基本都能定位。7. 更进一步请求防重、并发控制与云开发7.1 防止重复提交请求锁和带标识参数一个非常常见的业务场景是用户点击“提交订单”按钮网络慢时用户忍不住又点多下结果生成了两笔订单。处理方式有几种最简单的是按钮加 loading 和 disabled在请求完成前不允许再次点击。但这个方式挡不住某些极端情况比如用户快速双击loading 还没渲染出来。更可靠的是在请求封装层做防重比如同一个请求在短时间内重复调用时直接返回上一次的 Promise。const pendingMap new Map(); function requestWithDedupe(url, data) { const key ${url}-${JSON.stringify(data || {})}; if (pendingMap.has(key)) { return pendingMap.get(key); } const promise request(url, POST, data) .then((res) { pendingMap.delete(key); return res; }) .catch((err) { pendingMap.delete(key); throw err; }); pendingMap.set(key, promise); return promise; }这个逻辑不复杂但很实用。尤其是提交订单、支付这种敏感操作多用一层防重比依赖按钮状态稳妥得多。后端也应该做幂等校验比如用订单号或者请求唯一 ID这样即使前端重复提交后端也能识别出来。7.2 并行请求与竞态Promise.all 和请求过期丢弃有时候一个页面要同时拉取用户信息和配置项如果串行请求会明显增加等待时间。我一般直接用 Promise.all 并行请求async function initPage() { const [userInfo, config] await Promise.all([ get(/user/info), get(/config) ]); this.setData({ userInfo, config }); }这里有一个需要小心的点小程序页面切换很快时旧页面的请求结果可能在新页面加载后返回覆盖了新页面的数据。解决这类竞态问题的思路是在请求完成时判断当前页面是否已经被卸载或者用一个“序列号”标记最新的请求。具体做法不复杂主要是要有这个意识。7.3 取消请求用 RequestTask.abort如果你在页面里发起一个请求然后用户立刻返回上一页其实页面的请求并不会自动取消它可能还会回调 setData导致报错。虽然可以通过判断页面是否已经卸载来避免 setData但更干净的方案是用 wx.request 返回的 RequestTask 对象手动 abort。let requestTask null; function fetchData() { requestTask wx.request({ url: https://api.example.com/list, success(res) { // 处理数据 } }); } function cancelFetch() { if (requestTask) { requestTask.abort(); } }不过要注意abort 之后 fail 回调也会触发 errMsg 带 abort 相关字样你不要把它当真正的错误提示弹给用户。封装层里最好判断一下 errMsg 是否包含 abort如果包含就不做统一错误提示。7.4 云开发用云函数免去域名配置烦恼如果你的项目不想折腾服务器微信云开发是个不错的选项。云开发里用 wx.cloud.callFunction 调用云函数不需要配置 request 合法域名因为请求通过微信的云网关直接路由。云函数内部可以再请求外部 API也可以直接操作云数据库。调用方式类似wx.cloud.callFunction({ name: getArticle, data: { articleId: 10086 } }).then(res { console.log(res.result); });这种模式适合快速原型和小型项目省心。但如果你有复杂的服务端逻辑、已有的后端系统云开发反而会增加迁移成本。我的建议是新项目可以优先考虑云开发老项目或者团队已经有完善后端的情况老老实实用 wx.request 对接现有接口就行。8. 写在最后的一点体会我踩过不少小程序 API 的坑最大的感受是大部分问题都不是高深技术而是基础认知没对齐。域名白名单、请求头字段、状态码判断、参数结构这四样东西只要理解扎实了你对接任何第三方 API 都会顺很多。尤其是登录那套流程尽量设计成“静默获取 code、后端换 token、前端统一存储、请求拦截器自动附带”别把一堆登录逻辑散落在每个页面里。最后再分享一个小技巧在封装层把 console.log 统一加上请求方法和 url比如[request] GET /user/info可以按标签过滤日志调试时不会刷屏。再配合一个有缩进的 JSON 格式化函数打印请求参数和响应体排查参数问题会非常高效。希望这篇教程能让你少走点弯路。如果后面遇到具体的报错欢迎在评论区把报错信息和场景发出来我会尽量帮你一起分析。
返回列表