资讯专栏INFORMATION COLUMN

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

HollisChuang / 1837人阅读

摘要:本文由云社区发表绝大多数程序只考虑了接口正常工作的场景,而用户在使用我们的产品时遇到的各类异常,全都丢在看似的中。在面板,还可以对请求进行暂停延迟等网络异常的模拟。小程序实现最后,留一道思考题。

本文由云+社区发表

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

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

CGI 逻辑出错。如调用方入参缺失类业务逻辑报错;

服务不稳定。如服务器不稳定导致 nginx 各类 500、502,cgi 路径调整导致的 404

用户网络环境差。如,网络不稳定、网速慢、运营商劫持等

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

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

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

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

*/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 结构体的字段名很可能不同):

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 配置如下:

*/mock file://({"code":12345,"message":"some_logic_error"}) # 模拟业务逻辑异常
2、服务器异常处理

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

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 的模拟配置如下:

*/mock statusCode://502 # 模拟 HTTP 状态码异常
3、接口被劫持注入

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

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 模拟配置如下:

*/mock file://(
hijacking
{"code":0,"data":"success"}) # 模拟接口被劫持注入 1

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

*/mock file://({"code":0,"data":"success"}) htmlAppend://{hijacking.html} # 模拟接口被劫持注入 2

4、用户网络不稳定

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

*/mock reqDelay://10000 enable://abort # 模拟 10 秒超时后网络不通

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

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

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

小程序 fetch API 实现

最后,留一道思考题。

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

欢迎留言分享你的代码实现

此文已由作者授权腾讯云+社区发布

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100424.html

相关文章

  • 99%程序没有考虑网络异常?使用Fundebug.notify()主动上报

    摘要:而且官方也给出了示例在回调函数中上报异常为了确保完全掌握小程序的运行状况,我们将异常上报。的微信小程序插件除了可以自动捕获异常外,还支持通过接口主动上报异常。 近日看到一篇文章99%的程序都没有考虑的网络异常,开篇提到: 绝大多数程序只考虑了接口正常工作的场景,而用户在使用我们的产品时遇到的各类异常,全都丢在看似 ok 的 try catch 中。如果没有做好异常的兼容和兜底处理,会极...

    ChanceWong 评论0 收藏0
  • 道路千万条,安全第一条——一次服务器被入侵处理经过

    摘要:为了进一步确认,再次到威胁情报平台进行查询。再结合我部署的容器停止时间进行分析,应该是在我部署完成后几小时内服务器被入侵的。要从根本上解决问题需要进行溯源分析,避免服务器再次被入侵。结合以上线索以及个人经验分析,很可能利用的漏洞进行入侵的。 容器为何自动停止? 服务器为何操作卡顿? 进程的神秘连接到底指向何处? 发现——自动停止的容器 某日发现部署在服务器上的一个容器被停掉了,开始以为...

    aaron 评论0 收藏0
  • rancher使用感受以及与k8s对比

    摘要:但的数据存在,而的数据存储暂未了解但肯定是存在内存中。测试对比物理机进程。当然,使用对容器进行编排的时候,可以指定任何想要的网络方式如采用的方式,,。 简介: rancher 自带了一套网络方案,可以实现跨机器的docker容器互联。其原理大致是:在每个机器上通过docker启动一个路由容器,将docker容器启动时的ip定义为10.42网段,并在iptables中将10.42网段的请...

    dingda 评论0 收藏0
  • rancher使用感受以及与k8s对比

    摘要:但的数据存在,而的数据存储暂未了解但肯定是存在内存中。测试对比物理机进程。当然,使用对容器进行编排的时候,可以指定任何想要的网络方式如采用的方式,,。 简介: rancher 自带了一套网络方案,可以实现跨机器的docker容器互联。其原理大致是:在每个机器上通过docker启动一个路由容器,将docker容器启动时的ip定义为10.42网段,并在iptables中将10.42网段的请...

    _ang 评论0 收藏0
  • 一文梳理 RedHat 和 CentOS 运维中网络知识

    摘要:一系统运维中网络方面的规划与思考在很多公司,岗位职责都是很明确的,专职转岗,每人或者每组负责一块业务。二系统运维中网络方面操作梳理在系统运维中,经常涉及的网络方面的操作,一般由以下几个方面组成。初步意见,交换机上线这台机器所连端口。运维是一门艺术,也是一门苦差事,每个人对此均有不同的理解,正所谓一千个人眼中有一千个哈姆雷特。干一行就要爱一行,既然选择了这个行业,较好是能把它做到较好,发挥自己...

    Olivia 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<