您现在的位置是:首页 >技术交流 >【axios】vue中axios的请求配置网站首页技术交流

【axios】vue中axios的请求配置

林大大哟 2024-06-17 10:43:07
简介【axios】vue中axios的请求配置

注意:本文实例化为TS版

1、axios概念

axios 是一个基于 promise 封装的网络请求库,它是基于 原生XHR 进行二次封装,可以说是 XHR 的一个子集,而 XHR 又是 Ajax 的一个子集

特点

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

 2、接口列表

举例api文件夹在有个qrCode模块,里面存放我们要用的各个接口,那get,post等封装就放在request文件夹中,封装源码请参考第四点

import { get, post, formPost, exportExcel } from '@/request/index'

export function checkPdfRecord(params: object) {
  return get('/api/xxx', params)
}

export function updatePdf(params: object) {
  return post('/api/xxx', params)
}

3、调用实例

import {
    checkPdfRecord
  } from '@/api/qrCode';

checkPdfRecord(params).then(res => {
    }).finally(() => {
    })

4、源码 

核心文件展示

 1、index.ts

import axios from 'axios'
import NProgress from 'nprogress'
import { requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch } from './interceptors'
import { getPromise, formPostPromise, postPromise, exportPromise, uploadPromise, postExportPromise } from './requestPromise'

import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'

import { getSession } from '@/utils/storage'
const baseUrl = '' // 你的接口请求地址
const service: AxiosInstance = axios.create({
  baseURL: baseUrl,
  timeout: 10 * 1000, // 请求超时时间
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  }
})
// 请求前的处理
const requestHook = function (config: AxiosRequestConfig) {
  NProgress.start()
  const token = getSession('token')

  if (token) {
    config.headers.Authorization = token
  }
}
// 请求前的错误处理
const requestCatchHook = function (error: AxiosError) {
  console.log(error, 'requestCatchHook') // for debug
}

// 过期回调
const responseExpireHook = function (response: AxiosResponse) {
  // 过期回调处理 此处写你自己的逻辑
  return response
}

// 响应完成回调
const responseFinishCallback = function (e: any) {
  NProgress.done()
}

// request interceptor
service.interceptors.request.use(requestInterceptors(requestHook), requestInterceptorsCatch(requestCatchHook))

// response interceptor
service.interceptors.response.use(
  responseInterceptors(responseExpireHook, responseFinishCallback),
  responseInterceptorsCatch(responseExpireHook, responseFinishCallback)
)

export const get = (url: string, params?: any) => getPromise(service, url, params) // get 请求
export const post = (url: string, params?: any) => postPromise(service, url, params) // post 请求
export const formPost = (url: string, params?: any) => formPostPromise(service, url, params) // form post
export const exportExcel = (url: string, params: any) => exportPromise(service, url, params) // 导出
export const upload = (url: string, files: Blob, config?: AxiosRequestConfig) => uploadPromise(service, url, files, config) // 上传
export const postExcel = (url: string, paramss: any) => postExportPromise(service, url, paramss)

export default service

2、interceptors.ts

import type { AxiosRequestConfig, AxiosResponse, AxiosError, AxiosPromise } from 'axios'
import { ElMessage } from 'element-plus'

// 下面响应结果的结构为普遍使用,但可根据你们公司自己规则来定
interface Result<T = any> {
  code: number | string
  msg?: string
  message?: string
  data: T
}

export const requestInterceptors =
  (requestHook: Function) =>
  (config: AxiosRequestConfig): AxiosRequestConfig => {
    requestHook && requestHook(config)
    return config
  }

export const requestInterceptorsCatch =
  (requestCatchHook: Function) =>
  (error: AxiosError): AxiosPromise => {
    requestCatchHook && requestCatchHook(error)
    return Promise.reject(error)
  }

export const responseInterceptors =
  (responseHook: Function, responseCallback: Function) =>
  (response: AxiosResponse): any => {
    responseCallback && responseCallback(response)
    const res: Result = response.data
    if (response.config.responseType == 'blob') {
      return Promise.resolve(response)
    } else {
      if (res === void 0 || res === null || !res) {
        const message: string = `Error:${response.config.url} response.data is null or does not exist !`
        ElMessage.error(message)
        return Promise.reject(message)
      // 接口响应code码我默认1或者200是正常响应,这个值根据你们后端的逻辑来定噢
      } else if (res.code == 1 || res.code === 200) {
        // 正确响应
        res.data === null && console.log(response)
        return Promise.resolve(response)
      } else {
        return Promise.resolve(response)
      }
    }
  }

export const responseInterceptorsCatch =
  (responseCatchHook: Function, responseCallback: Function) =>
  (error: AxiosError): AxiosPromise => {
    responseCallback && responseCallback(error)
    if (error && error.response) {
      // 以下外部状态码是常规普遍使用的噢~你也可以根据你们公司自己逻辑来定
      switch (error.response.status) {
        case 400:
          error.message = '请求错误(400)'
          break
        case 401:
          error.message = '未授权,请重新登录(401)'
          break
        case 403:
          if (error.response.data && error.response.data.code === 5001) {
            error.message = error.response.data.msg
          } else {
            error.message = '拒绝访问(403)'
          }
          break
        case 404:
          error.message = '请求出错(404)'
          break
        case 408:
          error.message = '请求超时(408)'
          break
        case 500:
          error.message = '服务器错误(500)'
          break
        case 501:
          error.message = '服务未实现(501)'
          break
        case 502:
          error.message = '网络错误(502)'
          break
        case 503:
          error.message = '服务不可用(503)'
          break
        case 504:
          error.message = '网络超时(504)'
          break
        case 505:
          error.message = 'HTTP版本不受支持(505)'
          break
        default:
          error.message = `连接出错(${error.response.status})!`
      }
    }

    if (error.message && error.message.indexOf('timeout') !== -1) {
      error.message = '请求超时'
    }

    if (error.response?.data && error.response.data.code === 5001) {
      // 过期
      return responseCatchHook && responseCatchHook(error)
    }

    error.message && ElMessage.error(error.message)

    return Promise.reject({ ...error.response })
  }

3、requestPromise.ts

import type {
  AxiosInstance,
  AxiosRequestConfig
} from 'axios'

// 下面响应结果的结构为普遍使用,但可根据你们公司自己规则来定
interface Result<T = any> {
  code: number | string
  msg?: string
  message?: string
  data: T
}

// 默认格式下的post
export const postPromise = (service: AxiosInstance, url: string, params: any): Promise < Result > =>
  new Promise((resolve, reject) => {
    service
      .post(url, params)
      .then((response) => resolve(response.data))
      .catch((err) => {
        reject(err)
      })
  })

// 表单格式下的post
export const formPostPromise = (service: AxiosInstance, url: string, params: any): Promise < any > =>
  new Promise((resolve, reject) => {
    const formdata = new FormData()
    for (const [k, v] of Object.entries(params)) {
      formdata.append(k, v as string)
    }
    service
      .post(url, formdata)
      .then((response) => {
        resolve(response.data)
      })
      .catch((err) => {
        reject(err)
      })
  })

// 默认格式下的get
export const getPromise = (service: AxiosInstance, url: string, params: any): Promise < Result > =>
  new Promise((resolve, reject) => {
    service
      .get(url, {
        params
      })
      .then((response) => resolve(response.data))
      .catch((err) => {
        reject(err)
      })
  })

// 默认格式下的导出文件 post类型
export const postExportPromise = (service: AxiosInstance, url: string, params: any): Promise < any > =>
  new Promise((resolve, reject) => {
    service({
        method: 'post',
        url: url,
        data: {
          ...params
        },
        responseType: 'blob'
      })
      .then((response) => {
        const res = response.data
        const filename = decodeURI(response.headers['content-disposition'].split(';')[1].split('filename=')[1])
        resolve({
          res,
          filename
        })
      })
      .catch((err) => {
        reject(err)
      })
  })

// 默认格式下的导出文件 get类型
export const exportPromise = (service: AxiosInstance, url: string, params: any): Promise < any > =>
  new Promise((resolve, reject) => {
    service({
        method: 'get',
        url: url,
        params,
        responseType: 'blob'
      })
      .then((response) => {
        const res = response.data
        try {
          const filename = decodeURI(response.headers['content-disposition'] ?.split(';')[1].split('filename=')[1])
          let blob = new Blob([res])
          let downloadElement = document.createElement('a')
          let href = window.URL.createObjectURL(blob) //创建下载的链接
          downloadElement.href = href
          downloadElement.download = filename //下载后文件名
          document.body.appendChild(downloadElement)
          downloadElement.click() //点击下载
          document.body.removeChild(downloadElement) //下载完成移除元素
          window.URL.revokeObjectURL(href) //释放掉blob对象
          resolve({
            res,
            filename
          })
        } catch (error) {
          console.log(error)
          reject({
            res,
            filename: ''
          })
        }
      })
      .catch((err) => {
        reject(err)
      })
  })

// 表单格式下的上传文件
export const uploadPromise = (service: AxiosInstance, url: string, files: Blob, config?: AxiosRequestConfig): Promise < any > =>
  new Promise((resolve, reject) => {
    config && (config.headers['Content-Type'] = 'multipart/form-data')

    service
      .post(url, files, config)
      .then((res) => {
        resolve(res.data)
      })
      .catch((err) => {
        console.log(err, 'err')
        reject(err)
      })
  })

5、拓展知识

1、Fetch

Fetch是在 ES6 出现的,它使用了 ES6 提出的 promise 对象。它是 XMLHttpRequest 的替代品。

  • 使用 promise,不使用回调函数。
  • 采用模块化设计,比如 rep、res 等对象分散开来,比较友好。
  • 通过数据流对象处理数据,可以提高网站性能。

2、Ajax

Ajax 是一个技术统称,是一个概念模型,它囊括了很多技术,并不特指某一技术,它很重要的特性之一就是让页面实现局部刷新,是fetch和XMLHttpRequest的父级

3、多环境如何配置

根据环境变量文件来噢(开发模式或生产模式根据package.json)

package.json文件

"scripts": {
    "dev": "vite --mode development",
    "test": "vite --mode release",
    "buildTest": "vite build --mode release",
    "buildProduct": "vite build --mode production"
}

---本篇还是相当实用,喜欢就一键三连吧~欢迎评论---

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。