vue3 axios封装和环境变量
coderwxf 人气:4axios
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)
总结
加载全部内容