封装网络请求 
前言 
最近开新项目又得封装网络请求, 之前的用响应式变量有点折磨, 这次直接用 axios 了, 正好水一篇博客吧.
基本用法 
javascript
import axios from 'axios'
const instance = axios.create({
  baseURL: 'http://localhost:3000',
  timeout: 5000,
})
export { instance }对 response 和 request 的处理 
之后 axios.get 或者 post 什么的就行了. 但是用的时候会发现, 每次都需要这样子
javascript
// 这里假设100为请求成功, 1为token无效或缺少
//
// interface Response{
//  message: string,
//  code: number,
//  data: any
// }
//
//
instance.get('/info').then((res) => {
  if (!res.data) {
    // 数据为空
    return
  }
  const { code } = res.data
  if (code === 1) {
    router.push('/login')
    userStore.clear()
    showMsg('请重新登录')
  }
  const { data } = resp.data
  return data
})这样的话每次都需要判断 code, 然后从 res.data 里拿 data. 在页面里面其实并不关心 code, 如果能找个什么地方统一处理的话可以省好多事情.
axios 提供了两个拦截器, axios.interceptors.request.use和axios.interceptors.response.use, 一个针对请求, 一个针对回复. 在这里可以用回复来统一处理
javascript
const codeHandler = {
  // 处理业务错误
  1: () => {
    router.push('/login')
    userStore.clear()
    showMsg('请重新登录')
  },
}
const httpCodeHandler = {
  // 处理http状态码错误
  // ...
}
instance.interceptors.response.use(
  (resp) => {
    const { code } = resp.data
    if (code !== 100) {
      codeHandler[code]?.(resp)
      return promise.reject(resp)
    }
    const { data } = resp.data
    return data
  },
  (error) => {
    const { status } = error
    httpCodeHandler[status]?.()
    return Promise.reject(error)
  }
)这样子的话每次请求就可以直接使用 data 而不需要在意 code 了
javascript
instance
  .get('/info')
  .then((data) => {
    // 做点成功做的事情
  })
  .catch((err) => {
    console.error(err)
  })这里也可以用一下 request 的拦截器, 之后不用再手动加 token
javascript
instance.interceptors.request.use((config) => {
  if (!config.url.startsWith('/auth')) {
    // 不需要鉴权
    return config
  }
  // 获取token操作
  const token = localstorage.getItem('token')
  if (!token) {
    router.push('/login')
    return
  }
  config.headers.Authorization = `Bearer ${token}`
  return config
})解耦合 
写到这里之后用的还算方便, 如果业务逻辑一直这么简单的话. 但是随着项目的庞大, 这个可能就存在一点问题. 现在的话其实路由/页面、仓库、网络请求耦合在一起了, 在更加复杂的情况下要做修改就会相当痛苦. 这里可以用发布订阅的设计模式来解耦合.
javascript
class EventBus {
  on(eventName, listener) {
    if (!this.listeners[eventName]) {
      this.listeners[eventName] = new Set()
    }
    this.listeners[eventName].add(listener)
  }
  emit(eventName, ...args) {
    this.listeners[eventName].forEach(listener => listener(...args))
  }
  off(eventName, listener) {
    if (!this.listeners[eventName]) {
      throw new Error(`Event with name ${eventName} is not found`)
    }
    this.listeners[eventName].delete(listener)
  }
}
export default new EventBus()这样的话, 网络请求这里就不必再导入 useUserStore 和 useRouter 之类的函数了, 只需要导入 EventBus, 然后这样
网络请求
javascript
const codeHandler = {
  // 处理业务错误
  1: () => {
    eventBus.emit('API:UN_AUTH')
  },
}仓库
javascript
export const useUserStore = defineStore('user', () => {
  eventBus.on('API:UN_AUTH', () => {
    logout()
  })
  const userInfo = ref()
  const setUser = (user) => {
    userInfo.value = user
  }
  const logout = () => {
    userInfo.value = null
    localstorage.removeItem('token')
  }
  return {
    userInfo,
    setUser,
    logout,
  }
})路由
javascript
const router
	= createRouter()
	// ...
eventEmitter.on('API:UN_AUTH', () => {
  router.push('/auth/login')
})页面
javascript
eventEmitter.on('API:UN_AUTH', () => {
  showMsg('...')
})这样这几个部分只需要在自己的地方做好自己的事情就可以了.