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 data
case 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 } = response
if (!isSuccess) {
toast({
title: '网络异常请重启',
icon: 'error'
})
return Promise.reject(response)
}
switch ((data, code)) {
case 200:
return data
case 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'
break
case trial:
env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
break
case release:
env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
break
default:
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')