微信小程序111~120
1.完善请求-响应拦截器
如何判断成功还是失败?
- 如果成功,传递成功数据的同时新增 isSuccess:true字段
- 如果失败,传递失败数据的同时新增 isSuccess:false字段
1.使用请求
//配置请求拦截器
instance.interceptors.request = (config) => {const token = getStorage('token')if (token) {config.header['token'] = token}return config
}
//配置响应拦截器
instance.interceptors.response = async (response) => {return response
}switch ((data, code)) {case 200:return datacase 208:const res = await modal({content: '失败,请重新登录',showCancal: false})if (res) {clearStorage()wx.navigateTo({url: '/pages/login/login'})}return Promise.reject(response)default:toast({title: '程序出现异常,请联系客服或稍后重试'})return Promise.reject(response)
}
export default instance
2.请求封装-添加并发请求
- 使用 async 和await方式,当第一个请求结束以后才能发起第二个请求,会造成请求的阻塞,从而影响页面的渲染速度。
async allHandler () {await instance.get('/index/findBanner')await instance.get('/index/findBannerCategory1')await instance.get('/index/findBanner')await instance.get('/index/findBannerCategory1')}
- 使用 Promise.all() 方式,能将多个请求同时发送,不会造成堵塞,不影响速度。
async allHandler () {await Promise.all([instance.get('/index/findBanner'), instance.get('/index/findBannerCategory1'), instance.get('/index/findBanner'), instance.get('/index/findBannerCategory1')])}
封装一下:
all(...promise) {return Promise.all(promise)}
2.添加loading
- 在请求发送之前,需要通过wx.showLoading展示loading效果
- 服务器响应数据以后,需要调用wx.hideLoading隐藏loading效果
complete: () => {wx.hideLoading()
}
三个问题:
(1)每次请求都会执行 wx.showLoading(),但是页面中只会显示一个,后面的 loading 会将前面的覆盖。
(2)同时发起多次请求,只要有一个请求成功响应就会调用 wx.hideLoading,导致其他请求还没完成,也不会 loading。
(3)请求过快 或一个请求在另一个请求后立即触发,这时候会出现 loading 闪烁问题。
我解决这三个问题:首先在类中新增一个实例属性 queue,初始值是一个空数组
(1)发起请求之前,判断 queue 如果是空数组则显示 loading ,然后立即向 queue 新增请求标识。
(2)在 complete 中每次请求成功结束,从 queue 中移除一个请求标识,queue 为空时隐藏 loading。
(3)为了解决网络请求过快产生 loading 闪烁问题,可以使用定时器来做判断即可。
3.控制loading显示
需要一个开关来控制 loading 显示。
- 类内部设置默认请求参数 isLoading 属性,默认值是 true,在类内部根据 isLoading 属性做判断即可
- 某个接口不需要显示 loading 效果,可以在发送请求的时候,可以新增请求配置 isLoading 设置为 false
- 整个项目都不需要显示 loading 效果,可以在实例化的时候,传入 isLoading 配置为 false
defaults = {baseURL: '', // 请求基准地址url: '', // 接口的请求路径data: null, // 请求参数methods: 'GET', // 默认的请求方法// 请求头header: {'Content-type': 'application/json' // 设置数据的交互格式},timeout: 60000, // 默认的超时时长,默认为一分钟isLoading: true}if(options.loading) {
}
4.封装uploadAPI
将本地资源上传到服务器
wx.uploadFile({// 开发者服务器地址、接口地址url: '',// 要上传的文件路径filePath: avatarUrl,// 文件对应的key,服务器需要根据key来获取文件的二进制信息name: 'file',success: (res) => {// 服务器返回的数据是JSON字符串,要用JSON.parse转换res.data = JSON.parse(res.data)this.setData({avatarUrl: res.data.data})}
})
对其进行封装
(1)首先在WxRequest类内部创建upload实例方法,实例方法接收四个属性
return new Promise((resolve, reject) => {if (op.methods === 'UPLOAD') {wx.uploadFile({...options,success: (res) => {res.data = JSON.parse(res.data)// 合并参数const mergeRes = Object.assign({}, res, {config: options,isSuccess: true})resolve(this.interceptors.response(mergeRes))},fail: (err) => {const mergeRes = Object.assign({}, err, {config: options,isSuccess: false})reject(this.interceptors.response(mergeRes))}})} else {wx.request({...options,success: (res) => {resolve(res)},fail: (err) => {reject(err)}})}})
5.使用npm包发送请求
import WxRequest from 'mina-request'
import { getStorage, clearStorage } from './storage'
import { toast, modal } from './extendApi'
// 对 WxRequest 进行实例化
const instance = new WxRequest({baseURL: 'https://gmall-prod.atguigu.cn/mall-api', // 使用时请换成真实接口timeout: 1000, // 超时时长isLoading: false // 是否使用默认的 loading 效果
})// 添加请求拦截器
instance.interceptors.request = (config) => {const token = getStorage('token')if (token) {config.header['token'] = token}// 在发送请求之前做些什么return config
}// 添加响应拦截器
instance.interceptors.response = async (response) => {const { isSuccess, data } = responseif (!isSuccess) {toast({title: '网络异常请重启',icon: 'error'})return Promise.reject(response)}switch ((data, code)) {case 200:return datacase 208:const res = await modal({content: '鉴权失败,请重新登录',showCancal: false})if (res) {clearStorage()wx.navigateTo({url: '/pages/login/login'})}return Promise.reject(response)default:toast({title: '程序出现异常,请联系客服或稍后重试'})return Promise.reject(response)}// return response
}
// 导出实例
export default instance
6.小程序设置环境变量
开发环境需要调用开发板的接口地址,生产环境需要调用正式版的接口地址,小程序提供了wx.getAccountInfoSync()接口,获取当前账号信息。
开发版====>develop
体验版====>trial
正式版====>release
// 用来配置当前小程序项目的环境变量
const { miniProgram } = wx.getAccountInfoSync()
const { miniProgram } = miniProgram
let env = {baseURL: 'https://gmall-prod.atguigu.cn/mall-api'
}
switch (envVersion) {case develop:env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'breakcase trial:env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'breakcase release:env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'breakdefault:env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'break
}
export { env }
7.接口调用方式说明
一个接口是一个方法,每个方法需要单独导出
// 导入封装的网络请求模块实例
import http from '../utils/http'
// 获取首页轮播图数据
export const reqSwiperData = () => http.get('/index/findBanner')