Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 482|回复: 0

使用Typescript重构axios(九)——异常处理:基础版

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-28 05:54:07 | 显示全部楼层 |阅读模式

    0. 系列文章

    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条请求的响应信息都已经被打印出来了:

    • 第一条为请求成功状态,返回信息已经被打印出来
    • 第一条请求状态码为500,成功打印除了状态码信息Error: Request failed with status code 500
    • 第二条我们故意把请求的url写错,所以报了404错误,我们也成功打印出了错误信息;
    • 第三条响应超时,也打印出了超时信息Timeout of 2000 ms exceeded

    接着,我们刷新浏览器,然后迅速的在5秒之内点击F12network选项,把offline勾选上,此时表示浏览器网络断开,我们就能看到模拟网络错误情况。


    5. 遗留问题

    OK,三种异常情况虽然都已经成功处理了,但是这仅仅是错误的文本信息,对于排错来说极不方便,所以我们最好还能够返回错误属于哪个请求、请求的配置、响应对象等其它信息。那么,下篇文章我们就来继续补充,实现异常处理的增强版。
    (完)

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-1-11 15:10 , Processed in 0.058007 second(s), 27 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表