前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >99%的程序都没有考虑的网络异常

99%的程序都没有考虑的网络异常

原创
作者头像
猫哥学前班
发布于 2018-12-18 07:30:20
发布于 2018-12-18 07:30:20
1.6K00
代码可运行
举报
文章被收录于专栏:猫哥学前班猫哥学前班
运行总次数:0
代码可运行

绝大多数程序只考虑了接口正常工作的场景,而用户在使用我们的产品时遇到的各类异常,全都丢在看似 ok 的 try catch 中。如果没有做好异常的兼容和兜底处理,会极大的影响用户体验,严重的还会带来安全和资损风险。

接口异常,通常可以分为以下三类:

  • CGI 逻辑出错。如调用方入参缺失类业务逻辑报错;
  • 服务不稳定。服务器不稳定导致 nginx 各类 500、502,cgi 路径调整导致的 404
  • 用户网络环境差。如,网络不稳定、网速慢、运营商劫持等

那么,我们在写代码时,如何快速的模拟这些接口异常,做好程序的兼容处理呢?

今天向大家介绍网络调试神器 whistle 的网络异常调试方法,如果你还没用过 whistle,请参考《8102 年的程序员不需要 Hosts 和 Fiddler》。

假设我们有以下前端页面 index.html,放置在自己的本地路径:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<p id="success" style="color:green;"></p>
<p id="fail" style="color:red;"></p>
<script>
  fetch(`/mock?r=${Math.random()}`)
    .then(response => {
      return response.json()
    })
    .then(v => {
      document.getElementById('success').innerHTML = v.data;
    }).catch(err => {
      document.getElementById('fail').innerHTML = err.message;
    })
</script>

接下来,打开 whistle Rules 配置面板 http://127.0.0.1:8899/#rules ,配置模拟的 demo page 和 mock CGI:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*/mock file://({"code":0,"data":"success"}) # 配置 mock cgi 为模拟的 json 数据
example.com file:///Users/kaiye/Projects/Markdown/20181213/ # 配置任意域名到本地 demo 目录,这里注意替换成自己的路径

打开 http://example.com ,正常逻辑下页面展示出了绿色的 success ,现在我们开始加入一些网络异常。

1、业务逻辑异常处理

例如 CGI 没有返回 data 字段,而是返回了一个错误码 code 和对应的 message,针对这种业务逻辑异常我们只需在第二个 then 中做好 code 值的判断即可(注意,这里的 code、message、data 只是示例,实际业务 CGI 中的 JSON 结构体的字段名很可能不同):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fetch(`/mock?r=${Math.random()}`)
  .then(response => response.json())
  .then((v) => {
    // 业务逻辑异常处理
    if (v.code !== 0) {
      return Promise.reject(new Error(`ERROR_LOGIC_CODE:${v.code}`));
    }
    document.getElementById('success').innerHTML = v.data;
  })
  .catch((err) => {
    document.getElementById('fail').innerHTML = err.message;
  });

相应的 whistle 配置如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*/mock file://({"code":12345,"message":"some_logic_error"}) # 模拟业务逻辑异常

2、服务器异常处理

如果服务器直接抛出了 502 错误码,我们希望代码能给用户提示的同时,再做一个异常上报。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fetch(`/mock?r=${Math.random()}`)
  .then((response) => {
    // 服务器异常处理
    if (response.ok) {
      return response.json();
    }
    return Promise.reject(new Error(`ERROR_STATUS_CODE:${response.status}`));
  })
  .then((v) => {
    // 业务逻辑异常处理
    if (v.code !== 0) {
      return Promise.reject(new Error(`ERROR_LOGIC_CODE:${v.code}`));
    }
    document.getElementById('success').innerHTML = v.data;
  })
  .catch((err) => {
    const [type, value] = err.message.split(':');
    // 异常类型上报
    console.log(type, value);
    document.getElementById('fail').innerHTML = err.message;
  });

通过 whistle 的模拟配置如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*/mock statusCode://502 # 模拟 HTTP 状态码异常

3、接口被劫持注入

如果 CGI 被运营商劫持注入,可能导致接口返回一个不合法的 JSON 结构,最前面的 response.json() 会抛异常,我们可以提前 catch 住:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fetch(`/mock?r=${Math.random()}`).then((response) => {
  // 服务器异常处理
  if (response.ok) {
    return (
      response
        .json()
        // 接口数据解码异常处理
        .catch(err => Promise.reject(new Error('ERROR_DECODE_JSON')))
    );
  }
  return Promise.reject(new Error(`ERROR_STATUS_CODE:${response.status}`));
});

whistle 模拟配置如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*/mock file://(<div>hijacking</div>{"code":0,"data":"success"}) # 模拟接口被劫持注入 1

借助 htmlAppendvalues 配置,可以模拟更复杂的注入示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*/mock file://({"code":0,"data":"success"}) htmlAppend://{hijacking.html} # 模拟接口被劫持注入 2
```hijacking.html
<script>
alert('hijacking')
</script>
```

4、用户网络不稳定

如果我们要模拟请求发出 10 秒后断网或网络不通的情况,可以通过 whistle 这样配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*/mock reqDelay://10000 enable://abort # 模拟 10 秒超时后网络不通

让用户苦苦等待 10 秒,再报错的体验太糟糕。我们可以封装一个能配置超时时间的请求发送函数,同时把上面提到的错误异常都一起配置进来。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<p id="success" style="color:green;"></p>
<p id="fail" style="color:red;"></p>
<script>
  function myFetch(url, configOptions) {
    const options = Object.assign(
      {
        timeout: 3000
      },
      configOptions
    )
    const { timeout } = options
    return new Promise((resolve, reject) => {
      // 超时异常处理
      const timer = setTimeout(() => {
        reject(new Error(`ERROR_TIMEOUT:${timeout}`))
      }, timeout)
      fetch(url, options)
        .then(data => {
          clearTimeout(timer)
          resolve(data)
        })
        .catch(err => {
          clearTimeout(timer)
          reject(err)
        })
    })
      .then(response => {
        // 服务器异常处理
        if (response.ok) {
          return (
            response
              .json()
              // 接口数据解码异常处理
              .catch(err => Promise.reject(new Error('ERROR_DECODE_JSON')))
          )
        } else {
          return Promise.reject(
            new Error(`ERROR_STATUS_CODE:${response.status}`)
          )
        }
      })
      .then(v => {
        // 业务逻辑异常处理
        if (v.code !== 0) {
          return Promise.reject(new Error(`ERROR_LOGIC_CODE:${v.code}`))
        } else {
          return v.data
        }
      })
      .catch(err => {
        const [type, value] = err.message.split(':')
        // 异常类型上报
        console.log(type, value)
        return Promise.reject(err)
      })
  }
  myFetch(`/mock?r=${Math.random()}`)
    .then(data => {
      document.getElementById('success').innerHTML = data
    })
    .catch(err => {
      document.getElementById('fail').innerHTML = err.message
    })
</script>

这样,自定义的 myFetch 只需关注业务具体逻辑,针对不同的 catch error 做对应的处理。

除以上提到的协议命令字外,whistle 还支持 resSpeed 用于模拟低网速传输(单位:kb/s),tpl 协议则可以根据请求传入参数来动态模拟不同的数据在 Frames 面板,还可以对 WebSocket/Socket 请求进行暂停、延迟等网络异常的模拟。

小程序 fetch API 实现

最后,留一道思考题。

近来微信小程序开发非常火,小程序原生提供的 wx.request API 能用于发送 HTTPS 请求,请在它的基础之上进行封装,支持 promise 调用和 timeout 超时时间定义(小程序默认的请求超时定义在 app.json 中,不够灵活),并针对以上提到的 HTTP 状态码异常、接口劫持注入、慢网络、无网络状态等各种网络异常进行兼容处理。

欢迎留言分享你的代码实现,在公众号「猫哥学前班」中回复关键词 request ,可以参考我的实现和 whistle rules 配置。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Vue + Element UI 实现权限管理系统 前端篇(三):工具模块封装
使用axios发起一个请求是比较简单的事情,但是axios没有进行封装复用,项目越来越大,会引起越来越多的代码冗余,让代码变得越来越难维护。所以我们在这里先对 axios 进行二次封装,使项目中各个组件能够复用请求,让代码变得更容易维护。
朝雨忆轻尘
2019/06/19
5K1
Vue + Element UI 实现权限管理系统 前端篇(三):工具模块封装
99%的程序都没有考虑的网络异常?使用Fundebug.notify()主动上报
于是,笔者分析了 GitHub 上的一些开源微信小程序,发现大多数的代码异常处理确实是不够的。
Fundebug
2019/07/08
4770
pwa-之service worker 基本概念
pwa-之service worker 基本概念 pwa-之service worker 离线文件处理
frontoldman
2019/09/03
1.1K0
pwa-之service worker 基本概念
使用 Jest 进行前端单元测试
目前 Jest 已经在 Facebook 开源的 React, React Native 等前端项目中被做为标配测试框架。下面简单介绍一些 Jest 比较有用的功能和用法。
QQ音乐技术团队
2018/01/31
5.9K0
使用 Jest 进行前端单元测试
web H5摄像头-Media-Recorder-API-Demo
media-recorder-api <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>拍照2</title> </head> <body> <div style="display: block"> <button id="take" >拍照</button> <button onclick="upload()" >保存照片</button> <button
2021/11/08
5700
HarmonyOS 开发实践 —— 基于@ohos/axios的网络请求能力
Axios 是一个基于promise的网络请求库,可以运行node.js和浏览器中。基于Axios原库v1.3.4GitHub版本进行适配,使其可以运行在OpenHarmony并沿用其现有用法和特性。
小帅聊鸿蒙
2024/12/03
4700
HarmonyOS 开发实践 —— 基于@ohos/axios的网络请求能力
全面分析前端的网络请求方式
这种交互的的缺陷是显而易见的,任何和服务器的交互都需要刷新页面,用户体验非常差, Ajax的出现解决了这个问题。 Ajax全称 AsynchronousJavaScript+XML(异步 JavaScript和 XML)
ConardLi
2019/05/23
1.9K0
Python创建接口项目(FastAPI)及人脸识别
我们要实现一个人脸识别的功能,人脸识别的都是调用本地的图片,所以我们搭建一个接口服务来提供图片的上传。
码客说
2022/06/15
1.9K0
前端异常的捕获与处理
? 这是第 89 篇不掺水的原创,想要了解更多,请戳上方蓝色字体:政采云前端团队 关注我们吧~ 本文首发于政采云前端团队博客:前端异常的捕获与处理 https://www.zoo.team/arti
政采云前端团队
2021/03/16
3.8K0
前端异常的捕获与处理
Vue笔记:封装 axios 为插件使用
自从Vue2.0推荐大家使用 axios 开始,axios 被越来越多的人所了解。使用axios发起一个请求对大家来说是比较简单的事情,但是axios没有进行封装复用,项目越来越大,引起的代码冗余。就会非常麻烦的一件事。所以本文会详细的跟大家介绍,如何封装请求,并且在项目组件中复用请求。有需要的朋友可以做一下参考。
朝雨忆轻尘
2019/06/19
2K0
Vue笔记:封装 axios 为插件使用
前端防御性编程
一个页面在呈现给用户之前需要经过静态资源加载、后端接口请求和渲染这三个过程,我们要做的就是在各个过程中防御可能出现的异常情况,保持流畅的用户体验,同时还要应对来自外部的攻击。
用户4962466
2019/12/10
1.2K0
Promise 这个新 API 真香!
不过呢,就算有 Promise,有时候处理一些既可能是同步又可能是异步的函数,或者那种随时可能在启动时就给你扔个同步错误的函数,还是有点小别扭。
沉浸式趣谈
2025/04/28
990
vue3+element-plus+router+vuex+axios从零开始搭建(3)
现在在store文件夹下面新建四个文件state.js, mutations.js, getters.js, actions.js
solate
2021/06/22
3.8K0
vue3+element-plus+router+vuex+axios从零开始搭建(3)
搭建简易的物联网服务端和客户端-ECharts数据显示(七)
1)介绍 百度推出的一款纯 Javascript 的图表库。 官方网址:http://echarts.baidu.com/index.html 2)基本使用
治电小白菜
2020/08/25
1.2K0
搭建简易的物联网服务端和客户端-ECharts数据显示(七)
如何搭建前端异常监控系统
是指用户在使用应用时,无法得到预期的结果。不同的异常带来的后果程度不同,轻则引起用户使用不悦,重则导致产品无法使用,从而使用户丧失对产品的认可。
iOSSir
2020/07/24
1.9K0
如何搭建前端异常监控系统
如何搭建前端异常监控系统
是指用户在使用应用时,无法得到预期的结果。不同的异常带来的后果程度不同,轻则引起用户使用不悦,重则导致产品无法使用,从而使用户丧失对产品的认可。
发声的沉默者
2021/06/14
1.3K0
如何搭建前端异常监控系统
JS 调取摄像头
截止目前(2016-06-23)为止,js 调取摄像头实现视频聊天,部分浏览器还是不怎么支持的。
White feathe
2021/12/08
2.8K0
JS 调取摄像头
Fetch vs Axios
原文链接:https://meticulous.ai/blog/fetch-vs-axios/[1]
chuckQu
2022/08/19
1.4K0
Fetch vs Axios
分享我在 vue 项目中关于 api 请求的一些实现及项目框架
axios 默认提交格式为:application/json 可使用 qs 模块(需要安装)转换后提交格式为 application/x-www-form-urlencoded 通过设置 transformRequest 属性 data => qs.stringify(data) 可以正常表单形式提交
易墨
2018/09/14
1K0
分享我在 vue 项目中关于 api 请求的一些实现及项目框架
JavaScript 错误异常
JavaScript 错误异常 错误异常语句 try 语句测试代码块中的错误 catch 语句处理错误 throw 语句允许自定义错误 finally 语句在错误异常语句后,必须执行的代码块 try { adddlert("Hello") ; } catch (err) { document.getElementById("demo").innerHTML = err.message ; } // 结果 : adddlert is not defined JavaScript 将 addd
Mirror王宇阳
2020/11/12
5410
相关推荐
Vue + Element UI 实现权限管理系统 前端篇(三):工具模块封装
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验