平时开发React
或Vue
项目时,都是使用axios
第三方库来发起http
请求处理业务,由于会返回一个Promise
对象所以使用起来比较方便。在微信小程序中则提供了一个wx.request
的原生api
,但使用起来感觉并不好,所以手动封装一层Promise
来达到增强使用体验。
封装wx.request
import { removeToken,urlEncode } from "../utils/util";
// removeToken作用只是调用了wx.removeStorageSync删除一些数据
// urlEncode则是将对象解析成a=1&b=2参数格式
// 比较简单,按需实现即可
// 定义api服务地址
const baseUrl = 'http://dev.com:12345';
/**
* 传入请求参数,返回Promise支持链试调用
* @param url 请求地址
* @param method 请求方法类型,不传入默认是"GET"
* @param data 请求体数据
* @param params 请求参数
*/
function request(url, method = "GET", data = {}, params = {}) {
const header = {
"content-type": "application/json"
// 有其他content-type需求加点逻辑判断处理即可
}
// 获取token,有就丢进请求头
const tokenString = wx.getStorageSync("access_token");
if (tokenString) {
header.Authorization = `Bearer ${tokenString}`;
}
return new Promise(function (resolve, reject) {
// 判断是否传递了query参数,有则进行地址拼接
// if (params) {
// url += "?" + urlEncode(params)
// }
wx.request({
url: baseUrl + url,
method,
data,
dataType: "json", // 微信官方文档中介绍会对数据进行一次JSON.parse
header,
success(res) {
// HTTP状态码为200才视为成功
if (res.statusCode === 200) {
// 真正的数据响应体中还有一层success字段判断业务状态,按实际情况处理
if (res.data.success) {
resolve(res.data.result)
} else {
// 业务判断错误
reject(res)
}
} else if (res.statusCode === 401) {
// 删除token(401有可能是没穿token,token过期,token不合法等等)并重定向到登录页
removeToken();
wx.reLaunch({
url: "../login/login"
})
} else {
// wx.request的特性,只要有响应就会走success回调,所以在这里判断状态,非200的均视为请求失败
reject(res)
}
},
fail(err) {
// 断网、服务器挂了都会fail回调,直接reject即可
reject(err)
},
})
})
}
// 导出请求和服务地址
export { request, baseUrl}
wx.request
和前端常用库axios
有所区别,如当请求接口返回状态码为500
时,对于axios
来说Promise
状态会改为rejected
,并执行对应的回调。但是对于wx.request
来说,只要请求成功了,不管状态码是什么,都会走success
的回调,所以不能将请求失败的处理放入fail
中,fail
只有在如断网等请求没有成功发出处理时才会执行对应回调。
解决办法就是在success
回调中进行判断,如HTTP
状态码200
的视为成功并进入成功逻辑将状态改为fulfilled
(resolve
函数),其他则视为请求失败并将promise
状态改为rejected
(rejected
函数)
接口参数管理
在使用前,可以再通过一个类/函数去统一管理每个模块的接口,在业务逻辑中只需要调用对应的业务接口传参即可,不需要每次都编写冗余url,method,data
等等,下面用一个登录业务做例子
import { request } from "../request";
// 管理地址,个人习惯,喜欢的下载request参数中也行
const apiPath = {
login: "/api/v1/login"
}
class AuthService {
static login(data){
// 按住ctrl点击wx.request进入ts声明看options的类型,method是均大写的,对应即可
return request(apiPath.login, "GET", data)
// 由于request的参数顺序第四个才是查询参数,所以如果需要传递,第三个传输传空对象即可
// return request(apiPath.login, "GET", {}, data)
}
}
export default AuthService;
使用封装好的接口服务
import AuthService from "../../service/AuthService";
// 导入封装好的服务层
// 其他代码省略
page({
// Promise语法
submitForm(){
AuthService.login({username:"a",password:"2"}).then(res=>{
// 干点别的
},err=>{
// 出错了干点啥
})
},
// async-await语法糖
async asycsubmitForm(){
try{
const res = await AuthService.login({username:"abc",password:"123"});
// 干点别的
}catch(err){
// 错了干点啥?
}
}
})
现在可以愉快的在小程序开发中发起HTTP请求了。 完 :)