这个需求的应用场景是这样的,在开发一个基于h5的移动app 时,在请求api 时出现请求的异常或者是请求中途网络中断的情况,一旦出现问题则需要重新触发某个点击事件或者打开某个页面。于是就想,遇到异常情况我们能不能让请求自动重连,重新调用我们的数据。当然,一开始都是先看看网上的解决方案,但是找了好久没找到合适的(也可能是自己没找对关键词,当时搜索的是 “js断网重连机制”)。既然没有的话,就只好自己试一下了(要是哪位朋友有解决方案,希望可以分享一下)。
简单的整理一下需要的流程:
>发起请求
>如果请求正常,判断是否是期望的结果(这里说一下,一般我们的app 可以直接接我们开发的 后台 api,但是在做这个项目时有点不一样,在app与api之间多了一个第三方,我们的请求需要请求到第三方(jsp程序),然后第三方再请求我们的真实接口,有点绕,不能代理,第三方在请求异常或者超时时也有他们自己的消息返回,所以要做好判断是否是我们的数据)
>如果数据是我们能 api 返回的 执行 ajax 回调程序
>如果数据是第三方的异常数据 尝试重连(我们的 api 没问题的话,重新请求一般都是能得到数据的)
>如果请求异常 尝试重连
思路是这样,但具体实现还是有其它问题的。比如
1. 怎么确认是哪个请求出异常并对该请求重连呢?
2.重连的回调能否正常执行呢?
暂时不管上面两个问题,本文的解决发难如下
>建立一个 temp 数组来保存请求的记录,每一个调用 ajax 请求前都保存好必要信息:id(请求标识,标识不同的请求),url,data,callback,reloadtimes(重复请求次数) 。
>在请求进来时,判断是否已经在 temp中,不在的话,先保存到temp 中
>请求正常的话 从 temp 中移除
>请求异常的话,尝试重连
前面说了这么多,还是看看代码吧。
(function(window) {
var temp = new Array();
function removeTemp(obj) {
var id = obj.id;
//将请求记录从 temp 中去掉
for (var key in temp) {
if (id == temp[key].id) {
console.log("移除:" + temp[key].id);
temp.slice(key, 1);
break;
}
}
}
function reconnect(obj) {
var id = obj.id;
//这可以写更多的重连逻辑,比如 每次重连间隔的时间增加
if (obj.reloadtimes == 10) {
//将请求记录从 temp 中去掉
removeTemp(obj);
} else {
obj.reloadtimes++;
console.log(obj.id + " " + obj.reloadtimes + " 秒 后自动重新链接");
setTimeout(() => {
request(obj.id, obj.url, obj.data, obj.callback);
}, obj.reloadtimes * 1000); //每次间隔时间递增
}
}
//请求
function request(id, url, data, callback) {
let obj = {
id: id,
url: url,
data: data,
callback: callback,
reloadtimes: 0
};
//判断是否已经存在 缓存中了,存在则跳过
let exist = false;
for (let key in temp) {
if (id == temp[key].id) {
exist = true;
obj = temp[key];
break;
}
}
//不存在缓存中则插入
if (!exist)
temp.push(obj);
$.get(url, data, res => {
let _obj = obj;
//判断正常请求是否符合预期,这里判断结果内容是否大于XXX,实际上可以看情况处理
if (JSON.stringify(res).length > 5) {
//移除记录
removeTemp(_obj);
callback(res);
} else {
//重连
reconnect(_obj);
}
}).error(e => {
//重连
let _obj = obj;
console.log(_obj.id + " 请求异常");
reconnect(_obj);
//console.log(e);
});
//console.log(temp);
}
window.request = request;
}(window))
用的时候这样用就行了
//请求测试
request("aaaaaaa", "data.html", {}, res => {
console.log(res);
});
request("bbbbbbbb", "data1.html", {}, res => {
console.log(res);
});
request("ccccc", "data1.html", {}, res => {
console.log(res);
});
ps:这里的id 是随便写的 aaaaa 什么的,但实际开发的话,我们使用了 时间戳来作为id
效果如图
然后回头看下那两个问题
1.本文是通过创建一个对象数组保存了请求的必要信息,满足请求以及回调所需参数。
2.这个一开始担心的是多页面共同调用一个请求,要是切换到另一个页面会不会有问题,经实践发现没有问题(app 用的是 Hbuilder 开发)
ps:这里处理的是 ajax请求的,但是 如果不用ajax 不知道能否实现呢?还有就是,百度pc 端检索如果断网会定期请求重连,但处理方式好像不一样,哪位朋友了解的话,希望能分享一下,谢谢啦!