1.使用Typescript重构axios(一)——写在最前面
2.使用Typescript重构axios(二)——项目起手,跑通流程
3.使用Typescript重构axios(三)——实现基础功能:处理get请求url参数
4.使用Typescript重构axios(四)——实现基础功能:处理post请求参数
5.使用Typescript重构axios(五)——实现基础功能:处理请求的header
6.使用Typescript重构axios(六)——实现基础功能:获取响应数据
7.使用Typescript重构axios(七)——实现基础功能:处理响应header
8.使用Typescript重构axios(八)——实现基础功能:处理响应data
9.使用Typescript重构axios(九)——异常处理:基础版
10.使用Typescript重构axios(十)——异常处理:增强版
11.使用Typescript重构axios(十一)——接口扩展
12.使用Typescript重构axios(十二)——增加参数
13.使用Typescript重构axios(十三)——让响应数据支持泛型
14.使用Typescript重构axios(十四)——实现拦截器
15.使用Typescript重构axios(十五)——默认配置
16.使用Typescript重构axios(十六)——请求和响应数据配置化
17.使用Typescript重构axios(十七)——增加axios.create
18.使用Typescript重构axios(十八)——请求取消功能:总体思路
19.使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式
20.使用Typescript重构axios(二十)——请求取消功能:实现第一种使用方式
21.使用Typescript重构axios(二十一)——请求取消功能:添加axios.isCancel接口
22.使用Typescript重构axios(二十二)——请求取消功能:收尾
23.使用Typescript重构axios(二十三)——添加withCredentials属性
24.使用Typescript重构axios(二十四)——防御XSRF攻击
25.使用Typescript重构axios(二十五)——文件上传下载进度监控
26.使用Typescript重构axios(二十六)——添加HTTP授权auth属性
27.使用Typescript重构axios(二十七)——添加请求状态码合法性校验
28.使用Typescript重构axios(二十八)——自定义序列化请求参数
29.使用Typescript重构axios(二十九)——添加baseURL
30.使用Typescript重构axios(三十)——添加axios.getUri方法
31.使用Typescript重构axios(三十一)——添加axios.all和axios.spread方法
32.使用Typescript重构axios(三十二)——写在最后面(总结)
项目源码请猛戳这里!!!
1. 前言
在之前的文章中,虽然我们已经实现了 axios 的基本功能,但是那些都是正常情况,我们知道,在实际开发中,不可能没有错误发生。所以,接下来我们需要对一些常见的错误情况进行异常捕获和处理。我们期望,当异常出现时,我们都可以在 reject 回调函数中捕获到,如下形式:
axios({ method: 'get', url: '/api/handleError' }).then((res) => { console.log(res) }).catch((e) => { console.log(e) })
2. 需求分析
首先我们先来分析下一些常见的请求异常:
网络异常,当网络不通时抛出的异常; 请求超时,当请求发出后在指定时间内没有收到响应时抛出的异常。 状态码非200-300异常,当请求的状态码不在200-300之间时,我们也认为它出现了异常;OK,接下来,我们就对上面所列出的三种异常进行分别处理。
3. 异常处理
3.1 网络异常
当网络出现异常(比如不通)的时候发送请求会触发 XMLHttpRequest 对象实例的 error 事件,于是我们就可以在 onerror 的事件回调函数中捕获此类错误。
我们在 src/xhr.ts 中的 xhr 函数中添加如下代码:
// 4.1 网络错误事件 request.onerror = function() { reject(new Error("Net Error")); };
3.2 请求超时
在官方 axios 中,它允许用户在发请求时配置请求的超时时间 timeout ,也就是当请求发送后超过某个时间后仍然没收到响应,则请求自动终止,并会触发 XMLHttpRequest 对象实例的 ontimeout 事件。
1.首先,我们也要允许用户在发请求时可配置超时时间,所以我们在之前写好的请求参数接口类型 AxiosRequestConfig 里添加 timeout 选项,如下:
// src/types/index.ts export interface AxiosRequestConfig { url: string; method?: Method; headers?: any; data?: any; params?: any; responseType?: XMLHttpRequestResponseType; timeout?: number; }
2.接着,在 src/xhr.ts 中的 xhr 函数中获取用户配置的 timeout ,如果该参数不为空,则将其设置到 XMLHttpRequest 对象实例 request 上。
const {data = null,url,method = "get",headers,responseType,timeout} = config; if (timeout) { request.timeout = timeout; }
3.最后,我们通过注册 XMLHttpRequest 对象实例的 ontimeout 事件来捕获请求超时异常。
request.ontimeout = function() { reject(new Error(`Timeout of ${timeout} ms exceeded`)); };
3.3 非200-300状态码
对于一个正常的请求,往往会返回 200-300 之间的 HTTP 状态码,对于不在这个区间的状态码,我们也把它们认为是一种错误的情况做处理。
1.首先,我们先在 xhr 函数中的 onreadystatechange 的回调函数中,添加了对 request.status 的判断,因为当出现网络错误或者超时错误的时候,该值都为 0。
if (request.status === 0) { return; }
2.然后,我们再判断状态码是否在200-300之间,来决定是否抛出异常。
我们编写一个辅助函数 handleResponse ,如果状态码 response.status 在200-300之间,则 resolve(response) ,否则 reject 。
function handleResponse(response: AxiosResponse): void { if (response.status >= 200 && response.status < 300) { resolve(response); } else { reject(new Error(`Request failed with status code ${response.status}`)); } }
OK,三种异常处理就已经写完了,接下来我们就可以编写 demo ,来测试下效果如何。
4. demo编写
在 examples 目录下创建 handleError 目录,在 handleError 目录下创建 index.html :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>handleError demo</title> </head> <body> <script src="/__build__/handleError.js"></script> </body> </html>
接着再创建 app.ts 作为入口文件:
import axios from "src/index"; // 1.正常情况 axios({ method: "get", url: "/api/handleError" }) .then(res => { console.log(res); }) .catch(e => { console.log(e); }); // 2.url故意写错 axios({ method: "get", url: "/api/handleError1" }) .then(res => { console.log(res); }) .catch(e => { console.log(e); }); // 3. 模拟网络错误 setTimeout(() => { axios({ method: "get", url: "/api/handleError" }) .then(res => { console.log(res); }) .catch(e => { console.log(e); }); }, 5000); // // 4.配置请求超时时间为2秒,模拟请求超时 axios({ method: "get", url: "/api/handleError/timeout", timeout: 2000 }) .then(res => { console.log(res); }) .catch(e => { console.log(e.message); });
接着在 server/server.js 添加新的接口路由:
// 响应正常情况,有50%几率响应成功,有50%几率响应失败,返回状态码500 router.get('/api/handleError', function(req, res) { if (Math.random() > 0.5) { res.json({ msg: `hello world` }) } else { res.status(500) res.end() } }) // 响应请求超时情况,这里我们设置3秒后响应,而发请求那里设置了超时时间为3秒,所以会发生请求超时异常 router.get('/api/handleError/timeout', function(req, res) { setTimeout(() => { res.json({ msg: `hello world` }) }, 3000) })
最后在根目录下的 index.html 中加上启动该 demo 的入口:
<li><a href="examples/handleError">handleError</a></li>
OK,我们在命令行中执行:
# 同时开启客户端和服务端 npm run server | npm start
接着我们打开 chrome 浏览器,访问 http://localhost:8000/ 即可访问我们的 demo 了,我们点击 handleError ,通过 F12 的控制台我们可以看到:有3条请求的响应信息都已经被打印出来了:
接着,我们刷新浏览器,然后迅速的在5秒之内点击 F12 的 network 选项,把 offline 勾选上,此时表示浏览器网络断开,我们就能看到模拟网络错误情况。
5. 遗留问题
OK,三种异常情况虽然都已经成功处理了,但是这仅仅是错误的文本信息,对于排错来说极不方便,所以我们最好还能够返回错误属于哪个请求、请求的配置、响应对象等其它信息。那么,下篇文章我们就来继续补充,实现异常处理的增强版。
(完)
查看更多关于使用Typescript重构axios(九)——异常处理:基础版的详细内容...