【轮询】【ajax】【js】【spring boot】ajax超时请求:前端轮询处理超时请求解决方案 + spring boot服务设置接口超时时间的设置

 

 

场景描述:

ajax设置timeout在本机测试有效,但是在生产环境等外网环境无效的问题

 

1.ajax的timeout属性设置 前端请求超时事件【网络连接不稳定时候,就无效了】

var data = JSON字符串;
 $.ajax({
    type: "POST",
    url: url,
    dataType: 'json',
    timeout: 3000,//3s钟超时
    data: data,
    xhrFields: {
        withCredentials: true
    },
    success: function (json) {
        alert("保存成功")
    },
    error: function (err, textStatus, errorThrown) {
        alert("保存失败")
    }
});

 

属性说明:

timeout:  //单位是毫秒值   

timeout: 0  //代表永不超时 

 

其他说明:

当然,ajax里面设置的是前端超时事件,后端服务 的接口 也有超时时间。 
声明: timeout属性设置的超时时间,肯定是有效果的。
但是  在生产环境等时候,因为网络跳动不稳定,导致 前后端连接中断了,即使这里的超时时间设置再大  或者设置永不超时,也会进入error,即会发生超时情况。这种时候,就需要 在前端使用轮询去解决这种问题了。

 

 

 

2.spring boot为例,设置接口超时时间的两种方式

 

1> 在配置文件application.properties中加了spring.mvc.async.request-timeout=20000,意思是设置超时时间为20000ms即20s,
2>还有一种就是在config配置类中加入
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
        configurer.setDefaultTimeout(20000);
        configurer.registerCallableInterceptors(timeoutInterceptor());
    }
    @Bean
    public TimeoutCallableProcessingInterceptor timeoutInterceptor() {
        return new TimeoutCallableProcessingInterceptor();
    }
}

 

 

 

 

3.前端轮询方案 ,查询后端的保存状态,直到查询到后端的保存状态为成功,才做相应的用户响应操作 【解决ajax设置timeout避免不了的网络不稳定的问题】

轮询方案简介:

这里就要对 1中的 ajax进行改造了 。
这里使用 js的  setInterval()发起轮询     clearInterval()停止轮询


setInterval(code,millisec) 参数 描述 code 必需。要调用的函数或要执行的代码串。 millisec 必须。周期性执行或调用 code 之间的时间间隔,以毫秒计。 setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。 setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。

 

轮询方案代码:

 

//这是一个用户页面点击,并触发保存的方法入口
    clickAndSave(){
        loading.show();//选择你当前前端项目的loading组件,开启页面遮罩,提示用户,这会在等待响应呢
        var data = JSON字符串; //这个是页面上业务入参,或者是一些想要传入后端的参数
        var myFlag = new Date().getTime();     //作为本次保存的 唯一标识
        data.myFlag = myFlag;  //作为后端入参传给后台
        //开始正常的同步交互后端的请求
        $.ajax({
            type: "POST",
            url: url,
            dataType: 'json',
            timeout: 0,//永不超时
            data: data,
            xhrFields: {
                withCredentials: true
            },
            //网络正常且业务正常,进入这里
            success: function (json) {
                alert("处理成功的逻辑 依旧写在这里");
            },
            //网络异常或业务异常的 进入这里
            error: function (err, textStatus, errorThrown) {

                //网络异常,即此处要判断 error时候,是不是因为超时导致的,如果是超时导致的error,那就做轮询
                if (textStatus == 408 || textStatus == 'timeout') {
                    //轮询查询批量保存状态
                    //注意:setInterval()方法的第一个入参必须是function,否则,会被setInterval()方法认为传入的是目标函数执行完后的返回值,就导致了只会执行一次的现象
                    //所以要么按照方式一执行
                    window.myFlag2222 = setInterval(function (){
                        this.batchSaveTimer(myFlag);
                    },6000);
                    //要么按照方式二执行 ()=>的方式
                    //window.myFlag2222 = setInterval(() => this.batchSaveTimer(myFlag),2000);

                }else {
                //网络正常,未超时,但业务异常的进这里
                    loading.hide();//则关闭loading遮罩 并进行下面的正常业务异常的提示等动作
                    $('.J_button_submit').prop('disabled', false);
                    tips.show("保存失败");
                }
            }
        });
    },


    //轮询方法
    batchSaveTimer: function (flag) {

        $.ajax({
            type:'get',
            url: url + "/" + flag,
            dataType:'json',
            cache:true,
            xhrFields: {
                withCredentials: true
            },
            success:function(result) {
                if (result.code && result.code == 'success'  ) {

                //当后端保存状态为1  代表保存成功
                    if (result.data == '1') {

                        //这里就 停止轮询 入参一定是 发起轮询的setInterval()方法的返回值
                        clearInterval(window.myFlag2222);

                        alert("这里同样写一份  处理成功的逻辑");

                //当后端保存状态为-1 代表保存失败
                    } else if (result.data == '-1') {

                        //这里视业务而定,是否停止轮询
                        clearInterval(window.myFlag2222);

                        alert("这里写一份  处理失败的逻辑");
                    }
                }
            },
            error:function() {
                alert("服务器异常")
            }
        });


    },

 

 

 

 

 

附录说明:

当然,后端处理也很简单,在redis记录一个  status.
myFlag作为key
status作为value

开始保存,把status设置为0  开始处理
            status设置为1  处理成功
            status设置为-1 处理失败

 

posted @ 2020-04-26 15:48  Angel挤一挤  阅读(2825)  评论(0编辑  收藏  举报