axios的封装基于vite
- [什么是 Axios?](#什么是 Axios?)
- 一、安装
- 二、创建Axios实例
- 三、封装请求拦截request
-
-
- [3.1 统一设置token](#3.1 统一设置token)
- [3.2 处理无需token情况](#3.2 处理无需token情况)
- [3.3 动态处理FormData格式(比如文件上传)](#3.3 动态处理FormData格式(比如文件上传))
- [3.4 请求重试](#3.4 请求重试)
- [3.5 取消重复请求](#3.5 取消重复请求)
-
- 四、封装响应拦截response
- [五、封装 http 请求](#五、封装 http 请求)
- 六、使用
- 总结
什么是 Axios?
What is Axios?
Axios 是一个 基于 promise 的 HTTP 客户端,适用于 node.js 和浏览器。它提供了简洁的API、自动JSON数据转换、请求/响应拦截等强大功能。
一、安装
- 使用 npm:
npm install axios
- 使用 yarn:
yarn add axios
并在src文件夹下创建文件
二、创建Axios实例
在request文件下创建axios实例
javascript
import axios from 'axios'
const base = import.meta.env.VITE_APP_API // 接口地址
const service= axios.create({
baseURL: base,
timeout: 60000, // 设置超时时间
})
这里需要注意两点
- 需要在项目根目录下配置env环境文件
在vite中需要这样配置
必须使用VITE开头的配置信息 否则无法获取
javascript
NODE_ENV = "dev"
VITE_APP_ENV='dev'
//开发环境后端接口地址
VITE_APP_API='http://www.dev.com'
- 在package.json配置与env名字一样,来区分启动环境
javascript
"dev": "vite --mode dev",
"test": "vite build --mode test",
"build": "vite build --mode prod",
三、封装请求拦截request
3.1 统一设置token
javascript
service.interceptors.request.use(
(config: any) => {
// Do something before request is sent
const token = localStorage.getItem('access_token')
config.headers['X-Token'] = `Bearer ${token}` // 设置token
return config
},
(error) => {
// Do something with request error
return Promise.reject(error)
},
)
3.2 处理无需token情况
javascript
service.interceptors.request.use(
(config: any) => {
// Do something before request is sent
const needToken = !(config.params?.noToken || config.data?.noToken)
// 示例1:添加token
const token = localStorage.getItem('access_token')
if (needToken) {
config.headers['X-Token'] = `Bearer ${token}` // 设置token
}
delete config.params.noToken
return config
},
使用方法
javascript
let params = {
noToken: true,
}
const res = await getXXX(params)
3.3 动态处理FormData格式(比如文件上传)
javascript
if (config.data instanceof FormData) {
config.headers['Content-Type'] = 'multipart/form-data' // 文件上传
}
3.4 请求重试
javascript
const RETRY_COUNT = 3
let retry = 0 // 重试次数
service.interceptors.request.use(
(config: any) => {
// Do something before request is sent
config.metaData = { startTime: Date.now() }
return config
},
(error) => {
// Do something with request error
if (retry < RETRY_COUNT) {
retry++
console.warn(`请求超时,正在进行第 ${retry} 次重试...`)
return service.request(error.config)
}
return Promise.reject(error)
},
)
响应拦截里面
javascript
service.interceptors.response.use(
(response: any) => {
const endTime = Date.now()
const duration = endTime - response.config.metaData.startTime
console.log(`请求 ${response.config.url} 耗时 ${duration}ms`)
)
3.5 取消重复请求
应用条件:在某些情况下(例如网络连接不可用),尽早取消连接将使 axios 调用受益。如果不取消,axios 调用可能会挂起,直到父代码/堆栈超时(在服务器端应用中可能是几分钟)。
由于cancelToken
官网已经弃用这里就不再使用了,这里使用的是signal
这个方法。
在request文件下添加官网的这段代码
bash
function newAbortSignal(timeoutMs: number) {
const abortController = new AbortController()
setTimeout(() => abortController.abort(), timeoutMs || 0)
return abortController.signal
}
在请求拦截里面设置
bash
config.signal = newAbortSignal(config.timeout || 60000) // 超时控制
delete config.params.signal //删除请求参数
在http文件中设置
bash
.catch((err) => {
if (axios.isCancel(err)) {
console.log('请求超时自动取消', err.message)
}
})
使用
bash
const userLogin = async () => {
const controller = new AbortController()
let params = {
signal: controller.signal,
}
const res = await postLogin(params)
console.log(res)
}
将网络降一下速测试
打印
四、封装响应拦截response
javascript
service.interceptors.response.use(
(response: any) => {
// 2xx范围内的状态码触发
const res = response.data
// 自定义业务状态码处理
if (res.code !== 200) {
// 超出2xx范围的状态码 映射
const ERROR_MAP: Record<number, string> = {
400: '请求参数错误',
401: '认证过期,请重新登录',
403: '无权访问该资源',
500: '服务器开小差了,请稍后再试',
// 其他状态码
}
const { errCode, errMsg } = res
// HTTP状态码处理
const message = ERROR_MAP[errCode] || errMsg || '请求处理失败'
console.warn(message) // 错误信息提示
} else {
return res
}
},
(error) => {
return Promise.reject(error)
},
)
五、封装 http 请求
在http文件下创建axios实例
javascript
import service from './request'
import axios from 'axios'
const http = {
get(url: string, params: object) {
return service({
url,
method: 'GET',
params,
}).catch((err) => {
if (axios.isCancel(err)) {
console.log('请求超时自动取消', err.message)
}
})
},
post(url: string, data: any) {
return service({
url,
method: 'POST',
data,
}).catch((err) => {
if (axios.isCancel(err)) {
console.log('请求超时自动取消', err.message)
}
})
},
}
export default http
六、使用
在api文件夹下新建文件并引入
javascript
import http from '../http'
export const getLogin = (params: object) => http.get('/login', params) // 登录
export const getUserLogin = (data = {}) => http.get('/user/login' , data) //获取当前登录人信息
注:如果后端接口前缀有很多一样的可以新建文件再统一 引入
javascript
import { base1 , base2} from '../XXX'
export const getLogin = (params: object) => http.get(base + '/XXX', params) // 登录
export const getUserLogin = (params: object) => http.get(base2 + '/XXX', params) // 获取当前登录人信息
页面中引入接口并使用
javascript
const handleLogin = async () => {
const res = await getLogin ()
console.log(res)
}
总结
完整的request代码 ,其中一些细节根据不同项目需要不同调整~
bash
import axios from 'axios'
const base = import.meta.env.VITE_APP_API // 接口地址
const service = axios.create({
baseURL: base,
timeout: 60000, // 设置超时时间
// headers: { 'X-Custom-Header': 'foobar' }, // 设置请求头
})
//超时辅助函数
function newAbortSignal(timeoutMs: number) {
const abortController = new AbortController()
setTimeout(() => abortController.abort(), timeoutMs || 0)
return abortController.signal
}
const RETRY_COUNT = 3
let retry = 0 // 重试次数
service.interceptors.request.use(
(config: any) => {
// Do something before request is sent
console.log(config)
config.signal = newAbortSignal(config.timeout || 60000)
const needToken = !(config.params?.noToken || config.data?.noToken)
// 示例1:添加token
const token = localStorage.getItem('access_token')
if (needToken) {
config.headers['X-Token'] = `Bearer ${token}` // 根据服务器设置请求头
}
//示例2:不验证token
delete config.params.noToken
delete config.params.signal
// 示例3:Content-Type动态处理
if (config.data instanceof FormData) {
config.headers['Content-Type'] = 'multipart/form-data' // 文件上传
}
// 示例4:请求重试
config.metaData = { startTime: Date.now() }
return config
},
(error) => {
// Do something with request error
if (retry < RETRY_COUNT) {
retry++
console.warn(`请求超时,正在进行第 ${retry} 次重试...`)
return service.request(error.config)
}
return Promise.reject(error)
},
)
service.interceptors.response.use(
(response: any) => {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
console.log(response)
const endTime = Date.now()
const duration = endTime - response.config.metaData.startTime
console.log(`请求 ${response.config.url} 耗时 ${duration}ms`)
// 2xx范围内的状态码
// 统一处理数据结构
const res = response.data
// 自定义业务状态码处理
if (res.code !== 200) {
// 超出2xx范围的状态码 映射
const ERROR_MAP: Record<number, string> = {
400: '请求参数错误',
401: '认证过期,请重新登录',
403: '无权访问该资源',
500: '服务器开小差了,请稍后再试',
// 其他状态码
}
// 错误信息解析
const { errCode, errMsg } = res
// HTTP状态码处理
const message = ERROR_MAP[errCode] || errMsg || '请求处理失败'
console.warn(message) // 错误信息提示
} else {
return res
}
},
(error) => {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
console.log(error)
return Promise.reject(error)
},
)
export default service
参考 :axios官网