当前位置:   article > 正文

TS+Axios的封装(vue3.x环境)_vue3+ts封装axios

vue3+ts封装axios

1. 创建axios实例

  1. # 项目src下新建utils/request.ts
  2. # npm i axios 是必须滴
  3. import axios from 'axios'
  4. const baseURL = 'https://ilovesh.com' // 基地址
  5. const instance = axios.create({
  6. baseURL,
  7. timeout: 3000 // 请求超时时间 (3秒超时)
  8. })
  9. export { baseURL, instance }

2. 添加拦截器

  1. // 添加请求拦截器
  2. instance.interceptors.request.use(
  3. function (config) {
  4. // 在发送请求之前做些什么
  5. return config
  6. },
  7. function (error) {
  8. // 对请求错误做些什么
  9. return Promise.reject(error)
  10. }
  11. )
  12. // 添加响应拦截器
  13. instance.interceptors.response.use(
  14. function (response) {
  15. // 2xx 范围内的状态码都会触发该函数。
  16. // 对响应数据做点什么
  17. return response
  18. },
  19. function (error) {
  20. // 超出 2xx 范围的状态码都会触发该函数。
  21. // 对响应错误做点什么
  22. return Promise.reject(error)
  23. }
  24. )

3. 剥离数据

  1. // 把上图圈出的数据剥离出来
  2. // 修改响应拦截器的return值
  3. ...
  4. function (response) {
  5. // 2xx 范围内的状态码都会触发该函数。
  6. // 对响应数据做点什么
  7. return response.data
  8. }
  9. ...

4. 请求头携带Token

笔者首先在 App.vue 里写了个测试用例,先拿到Token:

  1. import { instance } from '@/utils/request'
  2. import { useUserStore } from '@/stores'
  3. // pinia仓库
  4. const userStore = useUserStore()
  5. instance
  6. .post('/login/password', {
  7. mobile: '13230000001',
  8. password: 'abc12345'
  9. })
  10. .then((res) => {
  11. // 调用仓库里的自定义存储方法 (现在仓库里有Token了)
  12. userStore.updateUser(res.data)
  13. })

接下来修改axios实例的请求拦截器(在请求头里携带Token):

  1. instance.interceptors.request.use(
  2. function (config) {
  3. // 在发送请求之前做些什么
  4. // 获取Pinia仓库
  5. const userStore = useUserStore()
  6. const token = userStore.user?.token
  7. if (token) {
  8. config.headers.Authorization = `Bearer ${token}`
  9. }
  10. return config
  11. },
  12. function (error) {
  13. // 对请求错误做些什么
  14. return Promise.reject(error)
  15. }
  16. )

配置完成后,最好能找个需要Token才能访问的接口测试一下!

5. 业务状态码出错的处理

这里指的是响应是成功的(2xx 范围内的状态码),业务是失败的。笔者这里的业务逻辑成功与否根据code区分,code = 10000 成功,code !== 10000 失败

 修改axios实例的响应拦截器:

  1. // 添加响应拦截器
  2. instance.interceptors.response.use(
  3. function (response) {
  4. // 2xx 范围内的状态码都会触发该函数
  5. // 对响应数据做点什么
  6. const { code, message } = response.data
  7. if (code !== 10000) return Toast(message) // 这里使用vant库的轻提示组件
  8. return response.data
  9. },
  10. function (error) {
  11. // 超出 2xx 范围的状态码都会触发该函数。
  12. // 对响应错误做点什么
  13. return Promise.reject(error)
  14. }
  15. )

6. 响应状态码401报错的处理

状态码 401 Unauthorized 代表客户端错误,指的是由于缺乏目标资源要求的身份验证凭证,发送的请求未得到满足。说人话就是“Token失效/出错”!

为了尽可能追求完美,这里的逻辑比较复杂:

① Token失效,使用路由转回登录页

② 假设在 abc 页面访问,这里发现 Token 失效了,我们使用路由转回了登录页;

        重新登录成功后,体验好的app会让我回到本来访问的abc页面,并且携带可能的路径参数;

③ 实现方式:把原本的页面路径&参数全部给到query带上,重新登录成功就能完美转回了;

        如何获取原本页面的路径&参数?使用 router.currentRoute.value.fullpath

  1. // 响应拦截器失败的函数内修改
  2. function (error: AxiosError) {
  3. // 超出 2xx 范围的状态码都会触发该函数
  4. // 对响应错误做点什么
  5. if (error.response?.status === 401) {
  6. // Pinia里删除用户信息
  7. const userStore = useUserStore()
  8. userStore.delUser()
  9. // 跳转登录,带上接口失效所在页面的地址,登录完成后回跳使用
  10. router.push({
  11. path: '/login',
  12. query: { redirectURL: router.currentRoute.value.fullPath }
  13. })
  14. }
  15. return Promise.reject(error)
  16. }

7. 封装请求函数&配泛型

  1. # 使用axios实例的伪代码
  2. instance({
  3. method: '',
  4. url: '',
  5. params / data (get请求的时候是params,get请求以外的是data)
  6. })
  7. # 希望封装一个函数,它的使用是 request<泛型>(url, method, 可能有/可能无的接口请求参数)

 雏形大概长这样:

  1. import axios, { AxiosError, type Method } from 'axios'
  2. // 请求工具函数
  3. const request = (url: string, method: Method = 'get', requestParams?: object) => {
  4. return instance.request({
  5. url,
  6. method,
  7. [method.toLowerCase() === 'get' ? 'params' : 'data']: requestParams
  8. })
  9. }
  10. // 按需导出
  11. export { baseURL, instance, request }

加上泛型的最终版

  1. // 这个需要替换 axios.request 默认的响应成功后的结果类型
  2. // 之前是:传 { name: string } 然后res是 res = { data: { name: string } }
  3. // 但现在:在响应拦截器中返回了 res.data 也就是将来响应成功后的结果,和上面的类型一致吗?
  4. // 所以要:request<数据类型,数据类型>() 这样才指定了 res.data 的类型
  5. // 但是呢:后台返回的数据结构相同,所以可以抽取相同的类型
  6. import axios, { AxiosError, type Method } from 'axios'
  7. type Data<T> = {
  8. // 内容根据接口返回的规则做修改
  9. code: number
  10. message: string
  11. data: T
  12. }
  13. // 请求工具函数
  14. const request = <T>(url: string, method: Method = 'get', requestParams?: object) => {
  15. return instance.request<T, Data<T>>({
  16. url,
  17. method,
  18. [method.toLowerCase() === 'get' ? 'params' : 'data']: requestParams
  19. })
  20. }
  21. // 按需导出
  22. export { baseURL, instance, request }

使用范例:

  1. import { request } from '@/utils/request'
  2. import type { User } from '@/types/user'
  3. request<User>('/login/password', 'post', {
  4. mobile: '13230000001',
  5. password: 'abc12345'
  6. }).then((res) => {
  7. // 调用仓库里的自定义存储方法
  8. userStore.updateUser(res.data)
  9. })

End-------------------

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/57133?site
推荐阅读
相关标签
  

闽ICP备14008679号