通用错误处理设计背景介绍

我们实际的开发业务,在前后端交互中错误一般会分为两类,一种实际业务错误,一种网络错误。结合我们上一篇文章中的通用返回模型,

  declare interface IResponse<T = any> {

    code: number

    msg: string

    data: T extends any ? T : T & any

  }

反应到http协议状态中:

一种是http状态码是非200的错误

另一种是http状态码是200的错误

我们在设计中一般会对非200的一些错误做重新登录处理(比如请求http的token过期的情况)或者重定向到错误页面

对于http状态码是200的业务错误,一般做重定向到具体的错误页面

基于上面的理解我们做以下的通用设计

1. 对于后端返回http 状态码 非200错误,

  •   http 状态码是401的,做重新登录处理
  •   http 状态码是404的重定向到404错误页面
  •   http 状态码是403的重定向到403错误页面,
  •   http 状态码是500转到500错误页面

2.对于后端返回http 状态码是200的 业务错误做了一个兼容性设计(有些设计把token错误和没有权限错误只表达在业务错误中):

  •     业务错误码是401的,做重新登录处理,
  •     业务错误码403的重定向到403错误页面,
  •     其他的业务错误重定向500错误(这里可以自定义一个错误页面,根据模型返回zh容进行,进行展示,为了简单我们直接重定向到element plus 提供的500页面)

通用错误处理代码修改

  http状态码是非200错误的修改

  在项目中找到文件src/axios/serivce.ts把28-40行做如下配置如下图,

axiosInstance.interceptors.response.use(
  (res: AxiosResponse) => {
    const url = res.config.url || ''
    abortControllerMap.delete(url)
    // 这里不能做任何处理,否则后面的 interceptors 拿不到完整的上下文了
    return res
  },
  (error: AxiosError) => {
    console.log('err: ' + error) // for debug
    ElMessage.error(error.message)
    return Promise.reject(error)
  }
)

替换为下面的代码

import router from '@/router'
import { useUserStoreWithOut } from '@/store/modules/user'
//用于处理http代码非200的错误代码
axiosInstance.interceptors.response.use(
  (res: AxiosResponse) => {
    const url = res.config.url || ''
    abortControllerMap.delete(url)
    // 这里不能做任何处理,否则后面的 interceptors 拿不到完整的上下文了
    return res
  },
  (error: AxiosError) => {
    console.log('aerr: ' + error, error.response?.status)
    // for debug
    //当http请求的状态码是401的时候跳转的到登录页面
    if (error.response?.status === 401) {
      const userStore = useUserStoreWithOut()
      userStore.logout()
    }
    //当http请求的状态码是500的时候跳转的到错误页面
    if (error.response?.status === 500) {
      router.replace('/error/500-demo')
    } else if (error.response?.status === 403) {
      router.replace('/error/403-demo')
    } else if (error.response?.status === 404) {
      router.replace('/error/404-demo')
    }
    ElMessage.error(error.message)
    return Promise.reject(error)
  }
)

http状态码200业务错误的修改代码

在项目中找到文件src/axios/config.ts把37-53行做如下配置如下图,

const defaultResponseInterceptors = (response: AxiosResponse) => {
  if (response?.config?.responseType === 'blob') {
    // 如果是文件流,直接过
    return response
  } else if (response.data.code === SUCCESS_CODE) {
    return response.data
  } else {
    ElMessage.error(response?.data?.message)
    if (response?.data?.code === 401) {
      const userStore = useUserStoreWithOut()
      userStore.logout()
    }
  }
}

替换为下面代码


import router from '@/router'
const defaultResponseInterceptors = (response: AxiosResponse) => {
  if (response?.config?.responseType === 'blob') {
    // 如果是文件流,直接过
    console.log('file stream', response?.config?.responseType)
    return response
  } else if (response.data.code === SUCCESS_CODE) {
    console.log('code 0 -----', response.data.code)
    return response.data
  } else {
    console.log('response data', response?.data?.code)
    ElMessage.error(response?.data?.msg)
    //当http请求的状态码是200, 业务的状态码是401的时候跳转的到登录页面
    if (response?.data?.code === 401) {
      const userStore = useUserStoreWithOut()
      userStore.logout()
    } else if (response?.data?.code === 403) {
      //当http请求的状态码是200, 业务的状态码是403的时候跳转的到403页面

      router.replace('/error/403-demo')
    } else {
      //当http请求的状态码是200, 业务状态码是其他错误的候跳转的500页面
      router.replace('/error/500-demo')
    }
  }
}

测试401错误情况:

可以在后端的 配置文件里application-test.yml 的配置项改为1,表示token 一分钟过期

app:
  console:
    token:
      expire: 1

登录一分钟后,操作退出系统操作就可以触发401错误,重定向到登录页面

测试404只需要访问一个不存在错误就可以了

开发环境访问自签名https后台

找到根目录下的vite.config.ts文件,修改147-157行的内容如下

    server: {
      port: 9801,
      proxy: {
        // 选项写法
        '/api': {
          target: 'http://127.0.0.1:8000',
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, '')
        },
         '/config/console':{
          target:'https://localhost:9200',
          changeOrigin:true,
        }
      },

修改为

   server: {
      port: 9801,
      proxy: {
        // 选项写法
        '/api': {
          target: 'http://127.0.0.1:8000',
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, '')
        },
         '/config/console':{
          target:'https://localhost:9200',
          changeOrigin:true,
          secure: false //不验证https证书
        }
      },

如果想使用自签名的https后端,只需要本文提供的测试后端,启动选择dev的配置文件即可

测试后端地址:  https://gitee.com/tigershi123/finance-back-parent.git

由于代码出错无法退出系统操作技巧

当代码错误无法退出时候,如果使用的是chrome浏览器,可以按F12进行调试模式,在应用选项卡上,存储位置,删除本地存储空间和会话存储空间的关于本项目url的内容,刷新后就会进入登录页面,如下图所示

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐