错误信息增强

需求分析

上一节课我们已经捕获了几类 AJAX 的错误,但是对于错误信息提供的非常有限,我们希望对外提供的信息不仅仅包含错误文本信息,还包括了请求对象配置 config,错误代码 codeXMLHttpRequest 对象实例 request以及自定义响应对象 response

  1. axios({
  2. method: 'get',
  3. url: '/error/timeout',
  4. timeout: 2000
  5. }).then((res) => {
  6. console.log(res)
  7. }).catch((e: AxiosError) => {
  8. console.log(e.message)
  9. console.log(e.request)
  10. console.log(e.code)
  11. })

这样对于应用方来说,他们就可以捕获到这些错误的详细信息,做进一步的处理。

那么接下来,我们就来对错误信息做增强。

创建 AxiosError 类

我们先来定义 AxiosError 类型接口,用于外部使用。

types/index.ts

  1. export interface AxiosError extends Error {
  2. config: AxiosRequestConfig
  3. code?: string
  4. request?: any
  5. response?: AxiosResponse
  6. isAxiosError: boolean
  7. }

接着我们创建 error.ts 文件,然后实现 AxiosError 类,它是继承于 Error 类。

helpers/error.ts

  1. import { AxiosRequestConfig, AxiosResponse } from '../types'
  2. export class AxiosError extends Error {
  3. isAxiosError: boolean
  4. config: AxiosRequestConfig
  5. code?: string | null
  6. request?: any
  7. response?: AxiosResponse
  8. constructor(
  9. message: string,
  10. config: AxiosRequestConfig,
  11. code?: string | null,
  12. request?: any,
  13. response?: AxiosResponse
  14. ) {
  15. super(message)
  16. this.config = config
  17. this.code = code
  18. this.request = request
  19. this.response = response
  20. this.isAxiosError = true
  21. Object.setPrototypeOf(this, AxiosError.prototype)
  22. }
  23. }
  24. export function createError(
  25. message: string,
  26. config: AxiosRequestConfig,
  27. code?: string | null,
  28. request?: any,
  29. response?: AxiosResponse
  30. ): AxiosError {
  31. const error = new AxiosError(message, config, code, request, response)
  32. return error
  33. }

AxiosError 继承于 Error 类,添加了一些自己的属性:configcoderequestresponseisAxiosError 等属性。这里要注意一点,我们使用了 Object.setPrototypeOf(this, AxiosError.prototype),这段代码的目的是为了解决 TypeScript 继承一些内置对象的时候的坑,参考

另外,为了方便使用,我们对外暴露了一个 createError 的工厂方法。

createError 方法应用

修改关于错误对象创建部分的逻辑,如下:

xhr.ts

  1. import { createError } from './helpers/error'
  2. request.onerror = function handleError() {
  3. reject(createError(
  4. 'Network Error',
  5. config,
  6. null,
  7. request
  8. ))
  9. }
  10. request.ontimeout = function handleTimeout() {
  11. reject(createError(
  12. `Timeout of ${config.timeout} ms exceeded`,
  13. config,
  14. 'ECONNABORTED',
  15. request
  16. ))
  17. }
  18. function handleResponse(response: AxiosResponse) {
  19. if (response.status >= 200 && response.status < 300) {
  20. resolve(response)
  21. } else {
  22. reject(createError(
  23. `Request failed with status code ${response.status}`,
  24. config,
  25. null,
  26. request,
  27. response
  28. ))
  29. }
  30. }

导出类型定义

在 demo 中,TypeScript 并不能把 e 参数推断为 AxiosError 类型,于是我们需要手动指明类型,为了让外部应用能引入 AxiosError 类型,我们也需要把它们导出。

我们创建 axios.ts 文件,把之前的 index.ts 的代码拷贝过去,然后修改 index.ts 的代码。

index.ts

  1. import axios from './axios'
  2. export * from './types'
  3. export default axios

这样我们在 demo 中就可以引入 AxiosError 类型了。

examples/error/app.ts

  1. import axios, { AxiosError } from '../../src/index'
  2. axios({
  3. method: 'get',
  4. url: '/error/timeout',
  5. timeout: 2000
  6. }).then((res) => {
  7. console.log(res)
  8. }).catch((e: AxiosError) => {
  9. console.log(e.message)
  10. console.log(e.code)
  11. })

至此,我们关于 ts-axios 的异常处理逻辑就告一段落。下面的章节,我们会对 ts-axios 的接口做扩展,让它提供更多好用和方便的 API。