绝大多数程序只考虑了接口正常工做的场景,而用户在使用咱们的产品时遇到的各种异常,全都丢在看似 ok 的 try catch 中。若是没有作好异常的兼容和兜底处理,会极大的影响用户体验,严重的还会带来安全和资损风险。html
接口异常,一般能够分为如下三类:前端
那么,咱们在写代码时,如何快速的模拟这些接口异常,作好程序的兼容处理呢?nginx
今天向你们介绍网络调试神器 whistle 的网络异常调试方法,若是你还没用过 whistle,请参考《8102 年的程序员不须要 Hosts 和 Fiddler》。程序员
假设咱们有如下前端页面 index.html,放置在本身的本地路径:web
<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:面试
*/mock file://({"code":0,"data":"success"}) # 配置 mock cgi 为模拟的 json 数据 example.com file:///Users/kaiye/Projects/Markdown/20181213/ # 配置任意域名到本地 demo 目录,这里注意替换成本身的路径
打开 http://example.com ,正常逻辑下页面展现出了绿色的 success ,如今咱们开始加入一些网络异常。json
例如 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"}) # 模拟业务逻辑异常
若是服务器直接抛出了 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 状态码异常
若是 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://(<div>hijacking</div>{"code":0,"data":"success"}) # 模拟接口被劫持注入 1
借助 htmlAppend 和 values 配置,能够模拟更复杂的注入示例:
*/mock file://({"code":0,"data":"success"}) htmlAppend://{hijacking.html} # 模拟接口被劫持注入 2 ```hijacking.html <script> alert('hijacking') </script> ```
若是咱们要模拟请求发出 10 秒后断网或网络不通的状况,能够经过 whistle 这样配置:
*/mock reqDelay://10000 enable://abort # 模拟 10 秒超时后网络不通
让用户苦苦等待 10 秒,再报错的体验太糟糕。咱们能够封装一个能配置超时时间的请求发送函数,同时把上面提到的错误异常都一块儿配置进来。
<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 请求进行暂停、延迟等网络异常的模拟。
欢迎工做一到五年的Java工程师朋友们加入Java架构开发:855801563
本群提供免费的学习指导 架构资料 以及免费的解答
不懂得问题均可以在本群提出来 以后还会有职业生涯规划以及面试指导
同时你们能够多多关注一下小编 纯干货 你们一块儿学习进步