美文网首页
四、错误处理-需求分析-网络错误+非200状态码

四、错误处理-需求分析-网络错误+非200状态码

作者: 雪燃归来 | 来源:发表于2020-04-21 23:21 被阅读0次

    在前一章节,我们实现了ts-axios的Promise封装和构建,完成了请求发送成功和成功获取数据后的处理操作。本篇我们将完成ts-axios面对各种错误时的处理方式。这些错误包括网络延时请求未找到(非200状态)服务器返回错误(500状态)等。

    一、修改xhr对象

    文件位置: /src/xhr.ts
    此处为了代码的完整性,我把整个代码片段都贴了出来。整体代码都比较直观,注释也比较详细。

    import { AxiosRequestConfig, AxiosPromise, AxiosResponse } from './types'
    import { parseHeaders } from './helpers/header'
    
    export default function xhr(config: AxiosRequestConfig): AxiosPromise {
      return new Promise((resolve, reject) => {
        const { data, url, method = 'get', headers, responseType, timeout } = config
        // 创建XHR请求对象的实例
        const request = new XMLHttpRequest()
        /**如果存在responseType */
        if (responseType) {
          request.responseType = responseType
        }
        /**设置请求时间 */
        if (timeout) {
          request.timeout = timeout
        }
        /**发送请求 */
        request.open(method.toUpperCase(), url, true)
        /**处理相应后的数据 */
        request.onreadystatechange = function handleLoad() {
          if (request.readyState !== 4) {
            return
          }
          if (request.status === 0) {
            return
          }
          const responseHeaders = parseHeaders(request.getAllResponseHeaders())
          const responseData = responseType !== 'text' ? request.response : request.responseText
          const response: AxiosResponse = {
            data: responseData,
            status: request.status,
            statusText: request.statusText,
            headers: responseHeaders,
            config,
            request
          }
          handleResponse(response)
        }
        /**网络错误处理 */
        request.onerror = function() {
          reject(new Error('Network Error!'))
        }
        /**处理请求错误 */
        request.ontimeout = function() {
          reject(new Error(`Timeout of ${timeout} ms exceeded`))
        }
        /**处理网络请求头 */
        Object.keys(headers).forEach(name => {
          if (data === null && name.toLowerCase() === 'content-type') {
            delete headers[name]
          } else {
            request.setRequestHeader(name, headers[name])
          }
        })
        request.send(data)
    
        // 处理状态码函数
        function handleResponse(response: AxiosResponse): void {
          if (response.status >= 200 && response.status < 300) {
            resolve(response)
          } else {
            reject(`Request failed with status code ${response.status}`)
          }
        }
      })
    }
    

    二、修改AxiosResponse接口类型,新增timeout属性

    文件位置: /src/types/index.ts

    export interface AxiosRequestConfig {
      url: string
      method?: Method
      data?: any
      params?: any
      headers?: any
      responseType?: XMLHttpRequestResponseType
      timeout?: number
    }
    

    三、编写测试用例

    import axios from '../../src/index'
    
    axios({
      method: 'get',
      url: '/error/get1'
    })
      .then(res => {
        console.log(res)
      })
      .catch(e => {
        console.log(e)
      })
    
    axios({
      method: 'get',
      url: '/error/get'
    })
      .then(res => {
        console.log(res)
      })
      .catch(e => {
        console.log(e)
      })
    
    setTimeout(() => {
      axios({
        method: 'get',
        url: '/error/get'
      })
        .then(res => {
          console.log(res)
        })
        .catch(e => {
          console.log(e)
        })
    }, 5000)
    

    在编写用例的时候,第三个测试用例需要我们注意一下。因为它没设置了5000ms后调用,这个用例是为了测试延迟函数调用的,所以我们应该遵循下面的操作流程。
    在请求刚开始的时候,将浏览器network面板中网络设置为online,然后这只为offline(5秒内),这样就可以测试超时调用了。

    四、优化错误处理

    通过上面的步骤,我们实现了对ts-axios错误的相关的处理,但是对于这样的处理来说,显得有些简单,因为我们只是简单的返回一段错误的提示,我们还应该将错误的编号、请求的配置等信息返回,方便我们快速定位错误。

    1、新增错误类型

    export interface AxiosError extends Error {
      isAxiosError: boolean
      config: AxiosRequestConfig
      code?: string | null
      request?: any
      response?: AxiosResponse
    }
    

    2、创建error处理函数

    文件位置 /src/helper/error.ts

    import { AxiosRequestConfig, AxiosResponse } from '../types'
    
    export class AxiosError extends Error {
      isAxiosError: boolean
      config: AxiosRequestConfig
      code?: string | null
      request?: any
      response?: AxiosResponse
    
      constructor(
        message: string,
        config: AxiosRequestConfig,
        code?: string | null,
        request?: any,
        response?: AxiosResponse
      ) {
        super(message)
        this.config = config
        this.code = code
        this.request = request
        this.response = response
        this.isAxiosError = true
    
        Object.setPrototypeOf(this, AxiosError.prototype)
      }
    }
    
    export function createError(
      message: string,
      config: AxiosRequestConfig,
      code?: string | null,
      request?: any,
      response?: AxiosResponse
    ): AxiosError {
      const error = new AxiosError(message, config, code, request, response)
      return error
    }
    

    3、重构错误返回值

    import { createError } from '../helpers/error'
    ...
    /**网络错误处理 */
    request.onerror = function() {
       reject(createError('Network Error!', config, null, request))
    }
    /**处理请求错误 */
    request.ontimeout = function() {
       reject(createError(`Timeout of ${timeout} ms exceeded`, config, null, request))
    }
    

    通过上面对错误处理的优化,我们可以返回更加确切的错误提示了,我们可以以下面的测试用例来检测一下我们优化的成果。

    axios({
      method: 'get',
      url: '/error/timeout',
      timeout: 2000
    })
      .then(res => {
        console.log(res)
      })
      .catch((e: AxiosError) => {
        console.log(e.message)
        console.log(e.config)
        console.log(e.code)
        console.log(e.request)
        console.log(e.isAxiosError)
      })
    

    相关文章

      网友评论

          本文标题:四、错误处理-需求分析-网络错误+非200状态码

          本文链接:https://www.haomeiwen.com/subject/gecvihtx.html