uni.request必须用promise封装才能被await正确调用,因其原生返回void;封装需将success/fail回调转为resolve/reject,统一处理状态码、错误及超时,并在async函数中配合try/catch使用。

uni.request 必须用 Promise 封装才能用 await
直接调用 uni.request() 返回的是 void,无法被 await,强行 await uni.request(...) 不会等待响应,而是立即往下执行。必须先把它包装成 Promise 实例,才能参与 async/await 流程。
封装的核心是把 success/fail 回调转为 resolve/reject 调用:
-
success中判断res.statusCode是否在 200–299 区间,是则resolve(res.data)(或完整res) -
fail或非 2xx 状态码时,统一reject(new Error(...)),便于上层catch - 别漏掉
dataType: 'json',否则某些平台(如 H5)可能返回字符串而非自动解析对象 - 建议默认加超时控制,比如
timeout: 10000,避免请求卡死无反馈
封装后如何在页面中正确使用 await
封装函数本身只是返回 Promise,真正起作用的是调用它的上下文必须是 async 函数。常见错误是写在 data()、computed 或普通 methods 里却没加 async 前缀。
正确写法示例:
async onLoad() {
try {
const res = await this.$http('/user/info', { uid: 123 });
this.userInfo = res;
} catch (err) {
uni.showToast({ title: '加载失败', icon: 'none' });
}
}
-
onLoad、onShow、自定义方法都需显式声明async - 务必用
try/catch捕获 reject,否则未处理的 Promise rejection 会静默失败 - 不要在
data()里 await —— 它不是异步函数,也不该承担数据获取职责
全局挂载 vs 模块导入:两种用法的区别
挂载到 Vue.prototype(如 this.$http)适合快速原型开发;模块导入(import request from '@/utils/request.js')更适合中大型项目,利于 tree-shaking 和类型推导。
- 挂载方式需在
main.js中执行Vue.prototype.$http = request,App/Vue2 有效;Vue3 + Composition API 需改用 provide/inject 或 pinia store 封装 - 模块导入更可控:可按需导入不同配置的实例(如带 token 的
authRequest、不带 header 的publicRequest) - 注意路径别写错:
import request from 'common/request.js'中的common是相对项目根目录,不是当前文件所在目录
容易忽略的拦截器和错误统一处理点
单纯 Promise 封装只解决“能 await”,但真实项目需要请求前自动加 token、响应后统一判错、网络异常弹 toast——这些得靠拦截器逻辑补全。
- 请求拦截:在
uni.request发起前读取uni.getStorageSync('token')并注入header.Authorization - 响应拦截:除 status code 判定外,还要检查后端自定义错误码(如
res.data.code !== 0),再 reject - 别在拦截器里直接调
uni.showToast,应由业务层决定是否提示;拦截器只负责抛错或转换格式 - 调试时留意:H5 端跨域、小程序域名白名单、App 端 HTTPS 强制要求,这些错误不会进
fail回调,而是直接触发catch,且err.errMsg内容各端不一致











