自学内容网 自学内容网

关于 vue3 axios的封装,并发请求相关

简介
Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

请求方法别名
为了方便起见,axios为所有支持的请求方法提供了别名(配置项在这里就不多做介绍,官网都有axios):

axios(config)

axios.request(config)

axios.get(url [,config])

axios.post(url [,data [,config]])

axios.put(url [,data [,config]])

axios.delete(url [,config])

axios.patch(url [,data [,config]])

axios.head(url [,config])

封装之前,需要下载axios依赖,这些准备工作做好后才能进行以下操作。

一,首先创建utils目录,在该目录下创建index.ts 文件,我这里用的是ts封装。

// 引入axios插件
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'
// import { ElMessage } from 'element-plus'

// 使用create 创建axios示例 (当然这里存在很多配置选项,具体需要具体配置)
const instance = axios.create()
// 我在这里直接指定了post请求的 请求类型 Content-Type,  可不设置看需要
instance.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8'

// 声明一个数组用于存储每个ajax请求的取消函数和ajax标识
const pending: any = []
const { CancelToken } = axios // axios 内置方法,此方法是为取消请求

// 入参removeAll 为true时,清空数组。
const removePending = (ever: AxiosRequestConfig, removeAll?: boolean) => {
  for (let i = 0; i < pending.length; i += 1) {
    if (removeAll) {
      pending[i].f() // 执行取消操作
      pending.splice(i, 1) // 把这条记录从数组中移除
    } else if (
      pending[i].u === `${ever.url!.replace(/d=\d+/, '')}&${ever.method}`
    ) {
      // 当当前请求在数组中存在时执行函数体
      pending[i].f() // 执行取消操作
      pending.splice(i, 1) // 把这条记录从数组中移除
    }
  }
}

const removeOtherPending = (ever: string, removeAll?: boolean) => {
  for (let i = 0; i < pending.length; i += 1) {
    if (pending[i].u.indexOf(ever) !== -1) {
      // 当当前请求在数组中存在时执行函数体
      pending[i].f() // 执行取消操作
      pending.splice(i, 1) // 把这条记录从数组中移除
    }
  }
}

// http request 拦截器
instance.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    // canMoreActive 参数用来判断是否需要被添加到pending队列中   该参数是设置在请求头中的,需要后台进行配置该参数
    if (!config.headers!.canMoreActive) {
      // 该接口是否可以多并发
      removePending(config) // 在一个ajax发送前执行一下取消操作
      // eslint-disable-next-line no-param-reassign
      config.cancelToken = new CancelToken((c) => {
        // 这里的ajax标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式
        pending.push({
          // 去除添加的日期导致的链接不一致
          u: `${config.url!.replace(/d=\d+/, '')}&${config.method}`,
          f: c,
        })
      })
    }
    return config
  },
  (error: AxiosError) => Promise.reject(error)
)


// 必须在项目中重写该方法,因为如果调用多次use方法,是一个队列,函数都会执行
/* instance.interceptors.response.use(
  (response: AxiosResponse) => {
    removePending(response.config) // 在一个ajax响应后再执行一下取消操作,把已经完成的请求从pending中移除
    if (response.data.code === 700) {
      ElMessage({
        type: 'error',
        message: response.data.msg,
      })
    }
    return response
  },
  (error: AxiosError) => Promise.reject(error)
) */

/**
 * 封装get方法
 * @param url 请求url
 * @param params 参数
 * @param config config参数
 * @returns {Promise}
 */
function fetch(
    url: string,
    params: any = {},
    config = {
        headers: {},
    }
): Promise<any> {
    return new Promise((resolve, reject) => {
        // 参数增加一个随机数解决浏览器缓存问题
        instance.get(`${url}?d=${new Date().getTime()}`, {
            params,
            headers: config.headers, // 设置get请求头,用来传递canMoreActive参数
        }).then((response) => {
            if (response) {
                resolve(response.data)
            }
        }).catch((err) => {
            reject(err)
        })
    })
}

/**
 * 封装post请求
 * @param url 请求url
 * @param data 参数
 * @param config config参数
 * @returns {Promise}
 */
function post(
    url: string,
    params: any = {},
    config = {},
    ContentType = ''
): Promise<any> {
    return new Promise((resolve, reject) => {
        if (ContentType) {
            instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
        } else {
            instance.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8'
        }
        instance.post(url, params, config).then((response) => {
            if (response) {
                resolve(response.data)
            }
        }).catch((err) => {
            reject(err)
        })
    })
}

/**
 * 封装 DELETE 请求
 * @param {string} url 请求的URL
 * @param {object} data 请求参数
 * @param {object} config 额外的 Axios 请求配置
 * @returns {Promise<any>}
 */
function del(
    url: string,
    data: any = {},
    config: AxiosRequestConfig = {}
): Promise<any> {
    return new Promise((resolve, reject) => {
        // 发起 DELETE 请求
        // 使用 delete 方法,注意要传递参数在 data 属性中
        instance.delete(url, {...config, data}).then((response: AxiosResponse) => {
            resolve(response.data) // 解析响应数据
        }).catch((error: AxiosError) => {
            reject(error) // 处理请求错误
        })
    })
}

// 全部导出
export { instance, post, fetch, pending, del, removePending, removeOtherPending }

以上大致封装完毕,导出相关用法。

二,在你项目结构中所适用的位置创建 index.ts 文件,我是在apis 目录下创建的。

// 引入上文index.ts 文件  可以决定路径,也可@/...(@代表src下)。
import {instance, removePending, post, fetch, del, pending,} from '这里是你上个文件创建的位置'
import { ElMessage } from 'element-plus'
// ts中 axios 类型
import { AxiosResponse, AxiosError } from 'axios'
// 这里是在外部文件 处理的baseUrl 基准地址,你也可以在上文中就约定好,一般基准地址都是动态的,不手动修改的
import * as base from './base'
import router from '@/router'

const instanceInit = () => {
  // 在这设置了基准地址 
  instance.defaults.baseURL = base.baseURL

  //
  instance.interceptors.response.use(
    (response: AxiosResponse) => {
      removePending(response.config) // 在一个ajax响应后再执行一下取消操作,把已经完成的请求从pending中移除

      if (response.data.code === 401 || response.data.code === '401') {
        ElMessage({
          type: 'warning',
          message: response.data.msg || '登录信息已过期,请重新登录!',
        })

        router.replace({path: '/login'})
        return Promise.reject()
      }
      return response
    },
    (error: AxiosError) => {
      // 当前接口不需要提示
      if (!error.config?.params?.noWarning) {
        ElMessage({
          type: 'warning',
          message: '系统错误,请联系管理员!',
        })
      }
      return Promise.reject(error)
    }
  )
}

export { instanceInit, instance, removePending, post, del, fetch, pending }

三,在 main.ts 中引入:

// 引入 上文声明 instanceInit 方法
import { instanceInit } from './apis/index'

instanceInit()

以上就是完整封装的axios, 里面包含注释。 如要登录后设置 请求头token, 可直接在拿到token后直接设置。

import { instance } from '@/apis/index'

instance.defaults.headers.common.Authorization =  '你的token'

四,下面来看一下使用示例:

首先可以分业务类型,功能模块去区分各个不同文件。在此就创建一个 equipment.ts 文件。文件中定义不同路径请求的api。可直接在 组件中引入使用。

// 引入封装好的  get  post 请求
import { fetch, post } from './index'

export const updateSuspectNoItemYet = {
  r: (params: any) => fetch('/suspect/updateSuspectNoItemYet', params),
}

export const listGoodsPage = {
  r: (params: any) => post('/goods/listGoodsPage', params, {
    headers: {
       // 这里设置 canMoreActive  说明该接口api 是可以并发的,多次请求。(也可在此配置 axios官网 所说的配置项 
      // eg: headers: { Authorization: 'Bearer 123' })
      canMoreActive: 'canMoreActive',
      // Authorization: 'Bearer 123'
    },
  }),
}


// 组件中 使用
import { listGoodsPage, updateSuspectNoItemYet  } from '@/apis/equipment'

const getList = async () => {
// params  入参  {id:'1',name: '测试'}
const res = await listGoodsPage.r(params)
}

以上就是完整的示例,欢迎评论区讨论,如有写的不足的地方欢迎指出。感谢点赞,收藏!


原文地址:https://blog.csdn.net/weixin_50559423/article/details/142487540

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!