提示:添加请求拦截器及封装请求方法
文章目录
(1) uni-app 中的拦截器语法
// STRING: 需要拦截的api名称, 比如 request、uploadFile 等
// OBJECT: 配置对象, 比如 invoke, 表示调用 api 后发送请求前执行的方法
uni.addInterceptor(STRING, OBJECT)
(2)实现请求拦截器中的逻辑
请求拦截器: 请求基准地址、超时时间、添加请求头标识 (Authorization、source-client)
// src/utils/request.ts
import { useMemberStore } from '@/stores'
// 请求基准地址
const baseURL = 'https://pcapi-xiaotuxian-front-devtest.itheima.net'
// 拦截器配置对象
const httpInterceptor = {
// 执行请求前触发
invoke(options: UniApp.RequestOptions) {
// 如果请求路径不是以 http 开头的
if (!options.url.startsWith('http')) {
// 将 url 参数拼接为完整路径
options.url = baseURL + options.url
}
// 更改请求超时时间, 该时间默认为 10s, 时间以毫秒为单位
options.timeout = 3000
// 添加请求头标识
options.header = {
...options.header,
'source-client': 'miniapp',
}
// 获取用于存储登录用户信息的 store 对象
const memberStore = useMemberStore()
// 获取用户登录凭据
const token = memberStore.profile?.token
// 如果 token 存在
if (token) {
// 将用户登录凭据添加到请求头中
options.header.Authorization = 'Bearer ' + token
}
},
}
// 对 request 方法进行拦截处理
uni.addInterceptor('request', httpInterceptor)
// 对 uploadFile 方法进行拦截处理
uni.addInterceptor('uploadFile', httpInterceptor)
(3) 封装请求函数并实现响应拦截器中的逻辑
要求函数返回 Promise, 方便函数的调用者使用 async await。
响应成功: 提取关键数据、为服务端返回数据添加类型
响应失败: 网络错误、401 错误、其他错误(服务端返回什么就提示什么)
① 封装返回 Promise 的请求函数并提取关键数据
// src/utils/request.ts
// 封装用于发送请求的方法
export const request = (options: UniApp.RequestOptions) => {
return new Promise((resolve, reject) => {
uni.request({
...options,
success: (response) => {
resolve(response.data)
},
})
})
}
② 为服务端返回数据添加类型
// 声明服务端返回的数据类型
interface Data<T> {
// 业务状态
code: string
// 提示消息
msg: string
// 数据
result: T
}
// 封装用于发送请求的方法
export const request = <T>(options: UniApp.RequestOptions) => {
// Promise 接收泛型参数, 用于标注成功状态下的数据的类型, 即调用 resolve 方法时传递的参数的类型
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
...options,
success: (response) => {
// 获取服务端返回的响应
const data = response.data as Data<T>
// 将 Promise 的状态设置为成功, 并传递服务端返回的响应
resolve(data)
},
})
})
}
③ 处理响应失败的情况
/ 封装用于发送请求的方法
export const request = <T>(options: UniApp.RequestOptions) => {
// Promise 接收泛型参数, 用于标注成功状态下的数据的类型, 即调用 resolve 方法时传递的参数的类型
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
...options,
success: (response) => {
// 获取服务端返回的响应
const data = response.data as Data<T>
// 注意: uni.request 方法没有处理响应状态码
// 也就是说只要服务端有响应, 无论该响应是成功状态还是失败状态都会执行 success 函数
// 所以此处我们需要手动判断状态下, 然后决定是执行请求成功的逻辑还是执行请求失败的逻辑
// 获取响应状态码
const statusCode = response.statusCode
// 如果请求状态是成功的
if (statusCode >= 200 && statusCode < 300) {
// 执行请求成功之后的逻辑
// 将 Promise 的状态设置为成功, 并传递服务端返回的响应
resolve(data)
// 如果请求状态是失败的, 且状态码为 401
} else if (statusCode === 401) {
// 401 错误
const memberStore = useMemberStore()
// 清空用户信息
memberStore.clearProfile()
// 跳转到登录页面
uni.navigateTo({ url: '/pages/login/login' })
// 将 promise 的状态设置为失败
reject(response)
// 如果请求状态为失败的, 且为通用错误
} else {
// 通用错误
uni.showToast({ icon: 'none', title: data.msg || '请求错误' })
// 将 promise 的状态设置为失败
reject(response)
}
},
fail: (error) => {
// 只有网络错误, 请求没有发出去才会执行当前函数
uni.showToast({ icon: 'none', title: '网络错误, 请换个网络试试' })
// 将 promise 的状态设置为失败
reject(error)
},
})
})
}