下面仅演示了 TS 中 axios 封装的基础版本(axios 基础封装 + 响应结果类型处理),更多版本可以查看个人项目:
https://github.com/Lencamo/request-tools
提示
在正式的开发中,Axios 请求封装往往伴随着 状态管理工具 的使用。
# 一、JS 环境中
# 1、结构
├── services
├── index.js
├── request # axios封装
│ ├── index.js
│ └── config.js
└── modules # api管理
├── cart.js
└── products.js
// @/services/index.js
import RenRequest from './request/index.js'
import { BASE_URL, TIMEOUT } from './request/config.js'
export const shopRequest = new RenRequest({
baseURL: BASE_URL,
timeout: TIMEOUT
})
export * from './modules/cart.js'
# 2、axios 封装
// @/services/request/config.js
export const BASE_URL = 'http://xxxxx.com'
export const TIMEOUT = 10000
// @/services/request/index.js
import axios from 'axios'
class RenRequest {
constructor(config) {
this.instance = axios.create(config)
// 响应拦截
this.instance.interceptors.response.use(
(response) => {
return response.data
},
(error) => {
return error
}
)
}
request(config) {
return this.instance.request(config)
}
get(config) {
return this.request({ ...config, method: 'get' })
}
post(config) {
return this.request({ ...config, method: 'post' })
}
}
export default RenRequest
# 3、api 管理
// @/services/modules/cart.js
import { shopRequest } from '../index.js'
export function getCartList(offset = 0, size = 20) {
return shopRequest.get({
url: 'carts/list',
params: {
offset,
size
}
})
}
# 4、使用示例(Vuex)
- vuex 中
vuex 模块化的目录结构
├── store
├── index.js
├── getters.js # 根级别的 getters
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js
└── products.js
// @/store/modules/cart.js
import { getCartList } from '@/services/modules/cart'
const state = {
cartList: []
}
const mutations = {
changeCartList(state, payload) {
state.cartList = payload.data
}
}
// 方式1
const actions = {
fetchCartListAction({ commit }, PageInfo) {
const { offset, size } = PageInfo
return new Promise((resolve) => {
getCartList(offset, size)
.then((res) => {
commit('changeCartList', { data: res.data }) // 修改state(在vuex中需要使用Mutations修改/更新数据)
resolve('修改state成功了')
})
.catch((error) => {
reject(error)
})
})
}
}
// 方式2
const actions = {
async fetchCartListAction({ commit }, PageInfo) {
const { page } = PageInfo
try {
const res = await getCartList(page * 20)
commit('changeCartList') // 修改state(在vuex中需要使用Mutations修改/更新数据)
} catch (err) {
console.log(err)
}
}
}
export default {
// 开启命名空间
namespaced: true,
state,
mutations,
actions
}
- 组件应用中
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapAction('cart', ['fetchCartListAction'])
// ======================
// fetchCartListAction() {
// this.$store.dispatch('cart/fetchCartListAction')
// }
}
}
</script>
# 二、TS 环境中
# 1、结构
├── services
├── index.ts
├── request # axios封装
│ ├── index.ts
│ └── config.ts
└── modules # api管理
├── cart.ts
└── products.ts
// @/services/index.ts
import RenRequest from './request/index'
import { BASE_URL, TIMEOUT } from './request/config'
export const testRequest = new RenRequest({
baseURL: BASE_URL,
timeout: TIMEOUT
})
export * from './modules/home'
# 2、axios 封装
// @/services/request/config.ts
export const BASE_URL = 'http://xxxxx.com'
export const TIMEOUT = 10000
// @/services/request/index.ts
import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
class RenRequest {
instance: AxiosInstance
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config)
// 响应拦截
this.instance.interceptors.response.use(
(response: AxiosResponse) => {
return response
},
(error: any) => {
return error
}
)
}
request(config: AxiosRequestConfig): Promise<AxiosResponse> {
return this.instance.request(config)
}
get<T = any>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
return this.request({ ...config, method: 'get' })
}
post<T = any>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
return this.request({ ...config, method: 'post' })
}
}
export default RenRequest
# 3、api 管理
// @/services/modules/cart.ts
import { testRequest } from '../index'
import type { AxiosResponse } from 'axios'
/**
* response数据类型
* - 【默认为any】
*/
interface IHomeData {
data: any
returnCode: string
success: boolean
}
export function getHomeList(
offset: number = 0,
size: number = 20
): Promise<AxiosResponse<IHomeData, any>> {
return testRequest.get<IHomeData>({
url: 'carts/list',
params: {
offset,
size
}
})
}
# 4、使用示例(Pinia)
- Pinia 中
Pinia 模块化的目录结构
Pinia 中的每一个文件就是一个单独的 store,所以不存在什么模块划分的说法。
├── stores
├── index.js
├── cart.js
└── products.js
// @/store/cart.js
import { getCartList } from '@/services/modules/cart'
export const useCounter = defineStore('main', {
state() {
return {
cartList: []
}
},
actions: {
// 方式1
fetchCartListAction(payload) {
const { offset, size } = payload
return new Promise((resolve) => {
getCartList(offset, size)
.then((res) => {
this.cartList = res.data // 可以直接修改state啦😘(再也不要像vuex那样commit、像redux那样和普通action区分了)
resolve('修改state成功了')
})
.catch((error) => {
reject(error)
})
})
},
// 方式2
async fetchCartListAction(payload) {
const { offset, size } = payload
try {
const res = await getCartList(offset, size)
this.cartList = res.data // 可以直接修改state啦😘(再也不要像vuex那样commit、像redux那样和普通action区分了)
} catch (err) {
console.log(err)
}
}
}
})
- 组件应用中
<script setup>
import { useCart } from '@/stores/cart'
const cartStore = useCart()
// 使用
// cartStore.fetchCartListAction()
</script>