axios

axios: ajax i/o system. 一个可以同时在浏览器和node环境进行网络请求的第三方库

功能特点:

  • 在浏览器中发送 XMLHttpRequests 请求
  • 在 node.js 中发送 http请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 等等

基本使用

get请求

// 导入的axios是一个实例对象
import axios from 'axios'

// axios方法返回的是promise
const res = await axios.get('https://httpbin.org/get', {
 	// 传递query参数
  params: {
    name: 'Klaus'
  }
})

// 服务器实际返回的数据被放置在data属性中
console.log(res.data)

post请求

const res = await axios.post('https://httpbin.org/post', {
  data: {
    name: 'Klaus'
  }
})

request请求

// axios的所有请求本质上都是在调用axios的request方法
const res = await axios.request({
  url: 'https://httpbin.org/post',
  method: 'post',
  data: {
    name: 'Klaus'
  }
})

all

axios.all本质上就是Promise.all

const res = await axios.all([
  axios.get('https://httpbin.org/get', {
    params: {
      name: 'Klaus'
    }
  }),

  axios.post('https://httpbin.org/post', {
    data: {
      name: 'Klaus'
    }
  })
])

拦截器

// 拦截器必须要在请求和响应之前被注册

// 请求拦截器 --- use方法的两个参数 --- 分别对应resolve和reject
// resolve方法的参数为请求的配置选项
// reject方法的参数为错误对象
axios.interceptors.request.use(
  config => {
    console.log(config)
    return config
  },
  err => console.error(err)
)

// 响应拦截器 --- use方法的两个参数 --- 分别对应resolve和reject
// resolve方法的参数为响应体
// reject方法的参数为错误对象
axios.interceptors.response.use(
  res => {
    return res.data
  },
  err => console.error(err)
)

配置

// 以下都是全局配置
// axios的所有全局配置都可以设置在属性defaults下

// 基本请求公共路径
axios.defaults.baseURL = 'http://httpbin.org'

// 超时时间
axios.defaults.timeout = 10000

// 需要传递的自定义请求头
axios.defaults.headers = {}
// 局部配置
axios
  .get('/get', {
  params: {
    name: 'Klaus',
    age: 18
  },
  
  // 局部配置可以覆盖全局配置
  timeout: 5000,
  headers: {}
})
  .then((res) => {
  console.log(res.data)
})

封装

如果直接在每一个需要进行网络请求的页面中的引入axios会导致如下问题:

  • 每一个页面都需要引入axios, 就导致axios和逻辑的耦合性过强,如果以后需要进行修改,那么就需要去每一个使用了axios的页面中进行修改

    是十分麻烦且容易出错的

  • 在页面请求的时候,我们会传递许多公共配置,例如BASE_URL,TOKEN等。

所以我们需要对我们的网络请求进行二次封装 --- 一般会放置在src下的service或者api文件夹下

type.ts

import { AxiosRequestConfig, AxiosResponse  } from 'axios'

// 自定义自己的拦截器类型
export interface Interceptor {
  requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig | Promise<AxiosRequestConfig>,
  requestInterceptorCatch?: (err: any) => any,
  responseInterceptor?: (res: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>,
  responseInterceptorCatch?: (err: any) => any,
}

// 通过接口继承的方式扩展axios的AxiosRequestConfig类型
export interface Config extends AxiosRequestConfig{
  interceptor?: Interceptor
}

env.ts

// 将一些相关配置配置成常量后在引入使用
// 将配置和调用解耦,如果需要修改,直接修改常量的值即可
export const TIME_OUT = 10000
export const BASE_URL = 'https://httpbin.org/'

index.ts

import Api from './api'

import {
  BASE_URL,
  TIME_OUT
} from './env'

const api = new Api({
  baseURL: BASE_URL,
  timeout: TIME_OUT,

  // 不同的实例可能有不同的拦截器
  // 所以我们将拦截器封装成一个扩展属性进行传入
  // interceptor: {
  //   requestInterceptor: config => {
  //     console.log('请求成功')
  //     return config
  //   },
  //   requestInterceptorCatch: err => console.error(err),
  //   responseInterceptor: res => res.data,
  //   responseInterceptorCatch:  err => console.error(err)
  // }
})

export default api

api.ts

import axios from 'axios'
import { ElLoading } from 'element-plus'
import type { AxiosInstance, AxiosRequestConfig } from 'axios'
import type { Config } from './type'

// 导出的属性和方法比较多 所以使用类来进行封装
// 因为类具有比较好的封装性
export default class {
  instance: AxiosInstance

  constructor(config: Config) {
    // 每次创建实例的时候,都调用axios.create方法
    // axios.create可以返回一个axios实例
    // 这样保证我们可以使用不同的配置创建多个axios实例
    this.instance = axios.create(config)

    // 如果存在实例级别的拦截器 就使用拦截器
    // 这是针对于每一个请求特有的拦截器 --- 实例拦截
    // 这里的操作也可以通过transformRequest和transformResponse配置项来进行实现
    if (config.interceptor) {
      const { interceptor } = config
      this.instance.interceptors.request.use(interceptor.requestInterceptor, interceptor.requestInterceptorCatch)
      this.instance.interceptors.response.use(interceptor.responseInterceptor, interceptor.responseInterceptorCatch)
    }

    this.registerGlobalInterceptor(config)
  }

  // 这是所有实例共有的拦截器 --- 全局拦截
  // 如果存在多个拦截器,那么多个拦截器都会被执行
  registerGlobalInterceptor(option: Config) {
    this.instance.interceptors.request.use(config => config, err => err)
    this.instance.interceptors.response.use(res => res.data, err => err)
  }

  request(config: AxiosRequestConfig) {
    return this.instance.request(config)
  }
}

请求时添加loading

import axios from 'axios'
import { ElLoading } from 'element-plus'
import type { AxiosInstance, AxiosRequestConfig } from 'axios'
import type { LoadingInstance } from 'element-plus/es/components/loading/src/loading'
import type { Config } from './type'

// el-loading是插件不是组件,element-plus的按需引入并不能正确的引入el-loading的样式
// 所以需要自己手动进行引入el-loading的样式
import 'element-plus/theme-chalk/el-loading.css'

export default class {
  instance: AxiosInstance
  loading: LoadingInstance | undefined

  constructor(config: Config) {
    this.instance = axios.create(config)

    if (config.interceptor) {
      const { interceptor } = config
      this.instance.interceptors.request.use(interceptor.requestInterceptor, interceptor.requestInterceptorCatch)
      this.instance.interceptors.response.use(interceptor.responseInterceptor, interceptor.responseInterceptorCatch)
    }

    this.registerGlobalInterceptor()
  }

  registerGlobalInterceptor() {
    this.instance.interceptors.request.use((config: Config) => {
      // ?? --- 当左侧的操作数为 null 或者 undefined 时,返回右侧操作数,否则返回左侧操作数
      if (config?.showLoading ?? true) {
        // 开启loading
        this.loading =  ElLoading.service({
          lock: true,
          text: 'Loading...',
          background: 'rgba(0, 0, 0, 0.7)',
        })
      }

      return config
    }, err => err)

    this.instance.interceptors.response.use(res => {
      // 关闭loading
      this.loading?.close()

      // axios返回的是字符串,所以需要反序列化
      return JSON.parse(res.data)
    }, err => {
      this.loading?.close()
      return err
    })
  }

  request(config: AxiosRequestConfig) {
    return this.instance.request(config)
  }
}

环境变量

在开发中,有时候我们需要根据不同的环境设置不同的环境变量,常见的有四种环境:

  • 开发环境: development
  • 生产环境: production
  • 测试环境: test
  • 预发布环境: stage

配置方式1: 手动的切换不同的环境(不推荐)

// 开发环境
// const BASE_URL = 'http://example.org/dev'
// const BASE_NAME = 'Klaus'

// 生产环境
// const BASE_URL = 'http://example.org/prod'
// const BASE_NAME = 'Alex'

// 测试环境
// const BASE_URL = 'http://example.org/test'
// const BASE_NAME = 'Steven'

配置方式2 --- 根据process.env.NODE_ENV的值进行区分

// vite默认会设置一下自带的环境变量
// 如  MODE, PROD, DEV, SSR, BASE_URL等
if (import.meta.env.MODE === 'development') {
 // ... do something
} else {
 // ... do else
}

配置方式3 --- 编写不同的环境变量配置文件

# .env.production
# 注意: 在vite中所有的环境变量必须以VITE_开头
VITE_APP_TITLE=My App in production
# .env.development
VITE_APP_TITLE=My App in development

vite在打包的时候,会自动根据开发环境注入不同的环境变量,我们可以读取这些环境变量并在需要的地方进行使用,如vite配置文件,src源代码中等等

// 使用
console.log(import.meta.env.VITE_APP_TITLE)

总结

到此这篇关于vue3实战教程之axios的封装和环境变量的文章就介绍到这了,更多相关vue3 axios封装和环境变量内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

vue3实战教程之axios的封装和环境变量的更多相关文章

  1. ios – 存档期间不存在Xcode环境变量

    我有一个具有TestFlight构建方案的iOS应用程序.在此方案中,我在“运行”选项卡中设置了一个称为TESTFLIGHT的环境变量,值为1.此外,在构建方案的“配置文件”选项卡中,它已选中“使用RUn操作的参数和变量”选项,并在列表中看到相应的EV.当从Xcode运行应用程序时,这可以正常工作,但是当我在存储设备上运行应用程序时,环境变量TESTFLIGHT不存在.我的问题是有一个我在这里缺少的选项/方案选项卡?

  2. Ubantu下配置swift开发环境

    恭喜.现在可以直接在这里写入临时的swift代码,注意是临时的.如果想要写swift,需要新建一个文件,比如touchhello.swift.用vim打开,在里面写入HelloWorld的代码,保存退出.编译上面的代码源文件,打开终端,找到源代码所在目录,输入命令swiftchello.swift,即可编译,如果没有出现错误,则说明编译成功.运行上面的hello,编译之后会出现一个新文件hello;这是ubantu的可执行文件,直接输入./hello即可执行

  3. android – 错误:程序“/ndk-build.cmd”在PATH中找不到

    按钮在出现的框中,选择名称字段并键入NDKROOT.在您解压缩AndroidNDK的路径中的值类型的字段中.点击“应用”,完成,对依赖NDK的任何其他项目进行此操作.

  4. 解决axios:"timeout of 5000ms exceeded"超时的问题

    这篇文章主要介绍了解决axios:"timeout of 5000ms exceeded"超时的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  5. 用vue3封装一个符合思维且简单实用的弹出层

    最近新项目中需要一个弹窗组件,所以我就做了一个,下面这篇文章主要给大家介绍了关于如何利用vue3封装一个符合思维且简单实用的弹出层,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

  6. Node.js中对通用模块的封装方法

    这篇文章主要介绍了Node.js中对通用模块的封装方法,封装方法参考了Underscore.js的实现,需要的朋友可以参考下

  7. java封装及四种权限修饰符详解

    这篇文章主要介绍了java封装及四种权限修饰符详解,对属性进行封装,使用户不能直接输入数据,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值

  8. 在vue中如何封装G2图表

    这篇文章主要介绍了在vue中如何封装G2图表,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  9. JS样式获取的封装方法实例详解

    这篇文章主要介绍了JS样式获取的封装方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  10. Ajax基础教程之封装(三)

    这篇文章给大家介绍ajax基础教程之封装的知识,本文通过实例给大家详细介绍,非常不错,感兴趣的朋友一起学习吧

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部