前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于TypeScript封装Axios笔记(四)

基于TypeScript封装Axios笔记(四)

作者头像
用户7572539
发布2020-08-26 10:02:44
8340
发布2020-08-26 10:02:44
举报
错误处理

需求分析

我们实现了 ts-axios 的基础功能,但目前为止我们都是处理了正常接收请求的逻辑,并没有考虑到任何错误情况的处理,这对于一个程序的健壮性而言是远不够的,因此我们这一章需要对 AJAX 各种错误情况做处理。

并且我们希望程序也能捕获到这些错误,做进一步的处理。‍

代码语言:javascript
复制
1axios({
2  method: 'get',
3  url: '/error/get'
4}).then((res) => {
5 console.log(res)
6}).catch((e) => {
7 console.log(e)
8})

如果在请求的过程中发生任何错误,我们都可以在 reject 回调函数中捕获到。

我们把错误分成了几类,接下来我们就来分别处理这些错误情况。

处理网络异常错误

当网络出现异常(比如不通)的时候发送请求会触发 XMLHttpRequest 对象实例的 error 事件,于是我们可以在 onerror 的事件回调函数中捕获此类错误‍。

我们在 xhr 函数中添加如下代码:

代码语言:javascript
复制
1request.onerror = function handleError() {
2  reject(new Error('Network Error'))
3}

处理超时错误

我们可以设置某个请求的超时时间 timeout,也就是当请求发送后超过某个时间后仍然没收到响应,则请求自动终止,并触发 timeout 事件。

请求默认的超时时间是 0,即永不超时。所以我们首先需要允许程序可以配置超时时间:

代码语言:javascript
复制
1export interface AxiosRequestConfig {
2 // ...
3  timeout?: number
4}

接着在 xhr 函数中添加如下代码:

代码语言:javascript
复制
1const { /*...*/ timeout } = config
2
3if (timeout) {
4  request.timeout = timeout
5}
6
7request.ontimeout = function handleTimeout() {
8  reject(new Error(`Timeout of ${timeout} ms exceeded`))
9}

处理非 200 状态码

对于一个正常的请求,往往会返回 200-300 之间的 HTTP 状态码,对于不在这个区间的状态码,我们也把它们认为是一种错误的情况做处理。

代码语言:javascript
复制
 1request.onreadystatechange = function handleLoad() {
 2 if (request.readyState !== 4) {
 3    return
 4  }
 5
 6 if (request.status === 0) {
 7    return
 8  }
 9
10 const responseHeaders = parseHeaders(request.getAllResponseHeaders())
11 const responseData =
12    responseType && responseType !== 'text' ? request.response : request.responseText
13 const response: AxiosResponse = {
14    data: responseData,
15    status: request.status,
16    statusText: request.statusText,
17    headers: responseHeaders,
18    config,
19 request
20  }
21  handleResponse(response)
22}
23
24function handleResponse(response: AxiosResponse) {
25 if (response.status >= 200 && response.status < 300) {
26    resolve(response)
27  } else {
28    reject(new Error(`Request failed with status code ${response.status}`))
29  }
30}

我们在 onreadystatechange 的回调函数中,添加了对 request.status 的判断,因为当出现网络错误或者超时错误的时候,该值都为 0。

接着我们在 handleResponse 函数中对 request.status 的值再次判断,如果是 2xx 的状态码,则认为是一个正常的请求,否则抛错‍。

demo 编写

在 examples 目录下创建 error 目录,在 error 目录下创建 index.html:

代码语言:javascript
复制
 1<!DOCTYPE html>
 2<html lang="en">
 3 <head>
 4 <meta charset="utf-8">
 5 <title>Error example</title>
 6 </head>
 7 <body>
 8 <script src="/__build__/error.js"></script>
 9 </body>
10</html>

接着创建 app.ts 作为入口文件:

代码语言:javascript
复制
 1import axios from '../../src/index'
 2
 3axios({
 4  method: 'get',
 5  url: '/error/get1'
 6}).then((res) => {
 7 console.log(res)
 8}).catch((e) => {
 9 console.log(e)
10})
11
12axios({
13  method: 'get',
14  url: '/error/get'
15}).then((res) => {
16 console.log(res)
17}).catch((e) => {
18 console.log(e)
19})
20
21setTimeout(() => {
22  axios({
23    method: 'get',
24    url: '/error/get'
25  }).then((res) => {
26 console.log(res)
27  }).catch((e) => {
28 console.log(e)
29  })
30}, 5000)
31
32axios({
33  method: 'get',
34  url: '/error/timeout',
35  timeout: 2000
36}).then((res) => {
37 console.log(res)
38}).catch((e) => {
39 console.log(e.message)
40})

接着在 server.js 添加新的接口路由:

代码语言:javascript
复制
 1router.get('/error/get', function(req, res) {
 2 if (Math.random() > 0.5) {
 3    res.json({
 4 msg: `hello world`
 5    })
 6  } else {
 7    res.status(500)
 8    res.end()
 9  }
10})
11
12router.get('/error/timeout', function(req, res) {
13  setTimeout(() => {
14    res.json({
15 msg: `hello world`
16    })
17  }, 3000)
18})

然后在命令行运行 npm run dev,接着打开 chrome 浏览器,访问 http://localhost:8080/ 即可访问我们的 demo 了,我们点到 Error 目录下,通过开发者工具的 network 部分我们可以看到不同的错误情况。

至此我们对各种错误都做了处理,并把它们抛给了程序应用方,让他们对错误可以做进一步的处理。但是这里我们的错误都仅仅是简单的 Error 实例,只有错误文本信息,并不包含是哪个请求、请求的配置、响应对象等其它信息。我们会对错误信息做增强。

错误信息增强

需求分析

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

代码语言:javascript
复制
 1axios({
 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:

代码语言:javascript
复制
1export 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:

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

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

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

createError 方法应用

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

xhr.ts:

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

导出类型定义

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

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

index.ts:

代码语言:javascript
复制
1import axios from './axios'
2
3export * from './types'
4
5export default axios

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

examples/error/app.ts:

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

至此,我们关于 ts-axios 的异常处理逻辑就告一段落。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 二少爷的花间集 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CLI 工具
云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档