ajax重复请求_ajax请求成功后如何让他不重复请求 - CSDN
  • 转载于:https://blog.fishlee.net/2016/07/07/double-request-from-wechat-client-with-ajax/ 背景 这是个大坑,耗费了我极多的时间。 ...作为一个单页面操作,所有请求都是通过AJAX和服务器...

    转载于:https://blog.fishlee.net/2016/07/07/double-request-from-wechat-client-with-ajax/

    背景

    这是个大坑,耗费了我极多的时间。

    事情呢,是这样的。最近几天做了一个微信里的潜入页,用于注册账户的。注册很简单,输入手机号-验证短信验证码-填一点资料-注册成功。

    作为一个单页面操作,所有请求都是通过AJAX和服务器交互的,这思路很常规。唯一的特点是,最后一步超长。

    超长的原因是:创建账户需要创建几百张表,还有无数初始化操作,所以乐观估计需要至少八秒钟才会成功。

    也许你会问为什么会这么慢,要创建这么多表呢?

    00089.gif

    原谅我不想说,因为与本文无关。

    00100.gif

    然则这个创建其实是有步骤的,第一步就是把用户的邮箱给占位:创建为最基本的信息,不允许重复创建

    OK,背景说完。

    直到上线

    开发,测试,包括内测都是很完美的,没有任何问题。

    但上线后,突然有测试提出了这么一个问题:微信里注册的时候,任何一个邮箱都会提示邮箱已使用

    面对这样一个错误且不管怎么换邮箱都同样的错误,所有人的表情都是懵逼的。

    00244.gif

    内心OS:这特么什么鬼。

    后端(Java,没错,语法和性能巨烂的Java):这是个很低级的BUG,很明显是服务器首次返回错误信息后乃们直接缓存了记录信息,所以后面其实都没验证。

    我还没去反驳,测试直接打脸。

    测试:我第一次输入就这样。
    Java:……

    Java同学陷入了沉思。
    反正我带着『不是自己问题』的乐观心态,坐在旁边看他们三脸懵逼。
    后来Java同学很不乐意地回去看了下数据库,发现邮箱确实存在了。
    Java同学一拍大腿,说哎呀你们这群测试都是猪呀,这明显存在嘛!

    测试的同学一脸懵逼,极不情愿地又用了一个小号邮箱重新注册,一样的错误。
    Java同学一查数据库,“行不行啊你们,这邮箱还是有啊”。
    测试同学一脸茫然,说我准备重新申请个QQ,你丫别吵吵……你看看XXX这个邮箱存不存在。
    Java:这个邮箱不存在。
    测试同学低头鼓捣了一下,说,“一样的错误”。
    Java同学低头查了一下,哎哟卧槽,怎么数据库有记录了,不是返回已存在了么。

    然后所有人都沉默了一下,最后他们把头一起转向我,表情是这样的。

    00160.gif

    他们:一定是你重复发请求却只拿最后一次请求当结果了。
    我直接甩锅:别看我,关我毛事,所有浏览器都测试过,按钮在发请求的时候都禁用了不可能重复点击,发请求状态都有标记不可能重复发,怎么可能发两次,你们别闹了,证据呢就乱说话。

    Java同学回去给代码加上Log输出,然后一边测一边看输出。

    然后他们看到了对我很不利的结果:

    “木鱼你看,你就是发出了两次请求嘛!”

    我看了看记录,特么的果然前后差了两秒钟,有两次开始执行记录的请求……

    我……

    00163.gif

    漫长地找原因

    我极不情愿地回来找前端的问题。

    然而我不管怎么看代码,怎么调试,怎么用自己的微信测试,不管是安卓(小米)还是iPhone5S,都测不出半点问题。从程序逻辑上看也根本没有发两次请求的机会。

    好郁闷……用了MVVM框架,难道这框架有问题??

    00130.gif

    然后我就开始怀疑是服务器那边的问题。Java的后端是跑在Tomcat上的,前面还有个Nginx做反代。于是我到运维那边找Ngxin的访问日志看了一下。

    查看了前后关联的请求,确实有重复的,但是客户端IP都不一样时间也不一样,而同一个IP的请求前后都是一个序列不存在重复

    所以根据Nginx的日志,很明显客户端没有重复请求啊,要是重复请求了,应该看到同一个IP的请求会重复出现才对。那么Java那边的重复记录怎么回事,难道Java这边自己调用了两次??

    看着Java同学那么天真的脸,我觉得把这个锅就这样甩给他们是莫大的伤害。

    于是我本着“有则改进无则加勉”的出发点,决定改前端代码。

    第一次尝试,在进入ajax方法之前,加一个bool变量标记,进入时加标记,完成后清除标记,进入之前判断是否已标记,如果已标记则直接退出。
    完全没改进,依然同样的错误。

    第二次尝试,将Ajax方法改成同步的,我直接阻止你浏览器操作,不能重复操作总不会因为DOM事件重复发了吧?
    完全没改进,依然同样的错误。

    第三次尝试,挂载全局的Ajax钩子,在ajax完成后打印返回结果到dom里。
    打印信息没重复,表明只收到了一个结果,那就是邮箱已存在。

    第四次尝试,直接上jQuery的AjaxFilter,将并行的重复ajax请求,直接截断。
    完全没结果。

    第五次尝试,在Ajax之前,设置了一个alert弹窗警告。
    神奇的,重复请求没了……

    00136.gif

    这特么都是什么跟什么啊。

    这个测试花了我很久,因为每次修改需要我提交,然后java那边打包,然后运维那边上测试环境,流程很漫长。

    此时,已经从晚上八点折腾到了十点多。

    为了尽快弄明白问题出在哪里,决定抓包测试。拿出自己的手机,用微信访问页面注册,完全没有任何问题。

    难道这和手机有关系?那出现这问题的手机也不是一部啊?拿了一部之前一直出问题的手机过来,连wifi设代理用Fiddler抓包。

    完全正常,没有任何问题,注册流程很正常。

    但是取消代理,就又只会报邮箱已存在的错误。

    What the f*ck……

    此时,已经是十一点多了。

    这时候,他们提出了一个很有建设性(才怪)的建议,就说是不是因为那个alert导致请求延迟了几秒才正常的,或者这是jQuery的问题?

    我很不情愿(并觉得他们纯粹是扯淡)地加了一个setTimeout测试。

    涛声依旧啊  00494.gif 

    到底咋回事?

    根据Java的输出,是有返回创建成功的消息的。

    然后我将所有的Ajax结果全部显示到DOM里,发现只有错误信息,却没有那个成功的信息。换句话说,如果请求确实重复发了,那么唯一能解释的是,js运行出错导致对应的消息没处理。

    然而新版本的安卓版微信自带浏览器内核,不是系统的webview,所以要调试只能用微信自己的工具。不过好歹可以测试。

    连上调试器,打断点,发现ajax函数只调用一次,没问题,但是唯一收到的消息就是返回了错误,却没有正常的结果。所以不是出错,而是确实就没有返回那个结果

    看到这样的结果,所有人暴躁了,这特么到底什么事啊。

    本来想在微信里抓包,然而微信调试工具里要抓包同样需要设代理,从之前测试的结果看,设代理就无此问题,又一次被卡住了。

    此刻,我的内心是崩溃的,难道真的只能洗洗睡了吗。

    00139.gif

    啊,看到了曙光

    此时,已经凌晨十二点多。为了尽快找到问题,后端的同学开始直接连上服务器实时输出Nginx的访问日志。

    神奇的,点击一次注册,滚动出了两条日志……(原谅我没截图)……我一眼看过去,哎卧槽这不是我之前看到的那俩IP么,咋这时候还在???

    看到的两条日志,除了客户端IP不一样之外,其它信息一模一样,包括地址、方法和UserAgent。客户端IP分别是123.151.42.57211.102.210.254211.102.210.254这个没啥问题,是这边的出口IP,那前面一个 123.151.42.57 是什么鬼?在ip138上查了一下,这是个天津的电信IP。然后这个IP的请求是先发出来的,比后面的请求提前了两秒钟,然而响应状态码是499,后面的是200

    499状态码是什么错误呢?搜索了一下Nginx的错误码,指出这个(非标)错误是指客户端关闭了连接。

    ……………………客户端关闭了连接????

    而邮箱已存在的错误,正是后面的那一条200请求返回的。

    PHP的同学一拍大腿,卧槽这不是说超时了么,你丫去把请求的超时设长一点。

    我不想跟他说话并想甩他一脸翔。

    『我之前为了避免此问题已经将超时设成5分钟了。』

    00288.gif

    不过此时,我开始关注那俩IP了……

    猜测

    事已至此,我唯一的猜测就是,微信的浏览器里发请求,并不是一定直接向服务器发送请求的,而是通过了某些特定的中转服务器进行转发。至于转发的原因,可能是为了重排版(将PC的网页压缩重排版以节约手机流量或适应大小)或加速(压缩)抑或安全检测(中转的时候拦截已知恶意网址)。往前面翻了一下,前面的几步流程都是123.151.42.57这个IP转发的,而最后一个注册请求发出来了却在2秒后又由211.102.210.254直接的连接发起……我只能解释为这个中转服务器的超时时间是两秒钟,为了防止服务器网络问题导致用户过长等待,默认如果请求2秒钟没返回则放弃中转改为直接发起。

    如果事实真如此,那么就能解释为什么前后会跟着两个请求,而前一个请求却在2秒钟后出499错误的情况了。
    那么为什么用代理的时候没有此问题?很容易解释,如果系统已经设置为通过代理服务器访问了,那么软件会直接假定无法直接联网或无法简单可靠地通过反代访问,所以会放弃中转。

    从前后间隔2秒的时间判断,大概超时时间就是2秒左右。那么可以做出假设,假定请求2秒钟内就会返回,则不会引发第二次请求。

    Java同学改了一下接口,先不做具体操作直接返回成功,测试了一下,果然就不会有此问题顺利走通流程。

    这个坑也是……活活把人坑到了凌晨1点。

    00742.gif

    后来作为改进的创建方案,Java端在确定可以创建后,直接返回成功,然后开后台任务异步创建。
    没有去校验创建是否成功,因为他们觉得失败概率很低,就算失败了其实也没有啥可重试的方法,还是先不检查算了。

    到此为止,问题顺利解决。

    重现

    现在问题解决了,但真正的问题还没解决:那就是我需要确定自己的结论。

    根据上面的判断,有这样的结论:

    1. 微信里直接发出ajax请求的话,其实是通过一些特定的服务器中转的
    2. 这个中转不是全部的,和手机以及系统有关系(因为我的安卓手机微信就没有这现象,而有此情况的手机也不是某个特定的品牌,iPhone也没此问题)
    3. 这个中转的超时时间很短,一旦超时,会迅速回滚为非中转模式请求

    但是这个模式有一个很致命的假定:就是它假定了所有的ajax请求都可以安全如此快速重试的,而没有考虑到关键请求处理时间较长且无法重复发送的情况(比如此例)。

    为了确定是否有此问题,我解析了一个测试域名 debug.fishlee.net,并模拟了一个带有长、短请求的测试页面,并开启跟踪。短请求即时返回,长请求则会阻断当前的操作10秒钟再结束。

    测试代码如下。

    <%@ Page Language="C#" AutoEventWireup="true" %>
     
    <script type="text/c#" runat="server">
     
        void Page_Load(object sender, EventArgs e)
    {
    var method = Request.HttpMethod;
            var action = Request.QueryString["action"];
            var startTime = DateTime.Now;
     
            if (method == "POST")
    {
    if (action == "slow")
    System.Threading.Thread.Sleep(10 * 1000);
                Response.Write((DateTime.Now - startTime).TotalMilliseconds.ToString());
                Response.End();
            }
    }
    </script>
    <!DOCTYPE html>
    <html>
    <head>
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>wxapi</title>
    <script src="http://static.fishlee.net/libs/jquery/1.12.4/jquery-1.12.4.min.js"></script>
    </head>
    <body>
    <button id="normalRequest" type="button">常规请求</button>
    <div></div>
    <button id="slowRequest" type="button">慢速请求</button>
    <div></div>
    <script>
    $(function () {
    $("#normalRequest").click(function () {
    $.post("?action=normal").always(function (data, option, xhr) {
    $("#normalRequest + div").html(xhr.responseText || "empty.");
                    });
                });
                $("#slowRequest").click(function () {
    $.post("?action=slow").always(function (data, option, xhr) {
    $("#slowRequest + div").html(xhr.responseText || "empty.");
                    });
                });
            });
        </script>
    </body>
    </html>

    并在 web.config 中开启跟踪。

    <?xml version="1.0"?>
    <configuration>
     <system.web>
         <httpRuntime targetFramework="4.5" />
         <trace enabled="true" requestLimit="100" pageOutput="false" />
     </system.web>
    </configuration>

    开启跟踪后,可以通过 /Trace.axd 查看跟踪结果。

    首先,我在自己的手机微信里,分别点击了两个按钮。跟踪显示,只有两个记录,并且客户端IP都是和我本机吻合的。

    然后我拿来他们测试有问题的手机,并在里面的微信中测试,分别点击。发现点击两次按钮,出现了三条记录。换句话说,问题复现了。

    double-request-from-wechat-001

    然后我们分别来看三个请求。

    第一个请求对应的是短请求,也就是发送后立马成功的那种,相当无脑。

    double-request-from-wechat-002

    从此图我们很明显可以看出,远程地址是 123.151.42.57,这并不是本地宽带的出口IP。从上面的判断可知,这是中转服务器,并且是确凿的,为什么呢,因为最下面有个 HTTP_X__FORWARDED_FOR 这个标头。为什么这么说呢,因为这个标头简直是反代服务器或代理服务器的一种标志性特征,它是为了告诉上游服务器,其实它是转发别人的请求来着的。

    然后我们来看第二个请求。

    double-request-from-wechat-003

    第二个请求是慢请求,除了操作参数不一样外,并没有不同,所有信息都和上面的请求完全一致。

    最后我们来看第三个请求。

    double-request-from-wechat-004

    和之前的相比,典型的不同就是,客户端IP已经成为211.102.210.254,对应的就是本地的出口IP,换句话说,这是没有通过中转服务器而直接访问源服务器了。
    因此,你也会看到下面的HTTP_X_FORWARDED_FOR标头已经不见了:因为不是中转了。

    至此,所有推论得到了论证。

    00746.gif

    总结

    复述一下第6节中的结论。

    1. 微信里直接发出ajax请求的话,其实是通过一些特定的服务器中转的
    2. 这个中转不是全部的,和手机以及系统有关系(因为我的安卓手机微信就没有这现象,而有此情况的手机也不是某个特定的品牌,iPhone也没此问题)
    3. 这个中转的超时时间很短,一旦超时,会迅速回滚为非中转模式请求

    至于这个中转到底什么情况下有,什么情况下没有,这个没有找到规律,也未知是微信中内嵌的浏览器内核行为还是系统行为。

    如果说非要做一点实质性的总结,那就是,如果假定你的请求是关键请求且难以重试还跑在微信中的,最好保证你的接口在两秒钟内返回,否则可能会有很诡异的难以复现的问题,如果时间过长的最好做成异步的。

    结案陈词,就是这种中转机制设计真的很糙,也不知道是哪里引入的。

    00628.gif

    话说回来,既然有此机制,我觉得应该就有后门:通过啥参数能阻止此中转,然而并没有找到。如果有同学知道的话,烦请告知~

    直到后来,用微信调试工具……

    事实胜于雄辩,我觉得单看问题就能猜到原因,我也是牛逼啊……23333

    double-request-from-wechat-005double-request-from-wechat-006

    嗯,欢迎扫描下方二维码关注鱼的公众号(微信内长按识别哦),也感谢阅读本文。 4.gif

     

     

    展开全文
  • 自己是一个刚从事前端开发工作的技术渣,在做项目完成后,测试发现有一个问题,我检查了一下,发现ajax重复调用一个数据接口,造成多次弹出请求后返回的信息。 自己网上查查了,找到了问题的原因和解决方法,在这里...

    自己是一个刚从事前端开发工作的技术渣,在做项目完成后,测试发现有一个问题,我检查了一下,发现ajax重复调用一个数据接口,造成多次弹出请求后返回的信息。

    自己网上查查了,找到了问题的原因和解决方法,在这里记录下来。

    1.造成重复提交原因

    由于AJAX提交数据为异步提交,所以当我们点击提交按钮是通过xmlhttprequest向服务器发送异步请求,发送请求需要有处理时间,我们第一次点击的请求尚未完成,就有接二连三的又提交了几次,同时后来发送的请求同事也被发送到后台处理了,这种情况如果是数据读取则不会有太大影响,但是涉及到数据提交保存或者提交之后多表数据处理就更麻烦了,所以此种情况务必要避免,免得给大家造成麻烦。

    2.解决办法

    1、如果提交对象为按钮的话,可以对按钮设置disabled,此办法适应于按钮提交,此种方法简单粗暴,也是很多人用的办法,代如下:

    $("input[type=submit]").attr('disabled',true)//在按钮提交之后和AJAX提交之前将按钮设置为禁用

    $.ajax({

    url:'/post.php'

    data:{a:1,b,1}

    success:function(){

    $("input[type=submit]").attr('disabled',false)//在提交成功之后重新启用该按钮

    },

    error: function(){

    $("input[type=submit]").attr('disabled',false)//即使AJAX失败也需要将按钮设置为可用状态,因为有可能是网络问题导致的失败,所以需要将按钮设置为可用

    }

    })

    经过以上对按钮的处理就避免了重复提交的问题

    2、非按钮对象提交

    有时候我们在提交数据的时候没有from,只有单个表单组件(input、textarea、radio、checkbox等),所以我们就可以将任何一个对象设置提交对象来完成提交,由于普通对象没有disabled属性,所以我们需要用其它方式来防止重复提交

    var post_flag = false; //设置一个对象来控制是否进入AJAX过程

    function post(){

    if(post_flag) return; //如果正在提交则直接返回,停止执行

    post_flag = true;//标记当前状态为正在提交状态

    $.ajax({//进入AJAX提交过程

    url:'/post.php'

    data:{a:1,b,1}

    success:function(){

    post_flag =false; //在提交成功之后将标志标记为可提交状态

    },

    error: function(){

    post_flag =false; //AJAX失败也需要将标志标记为可提交状态

    }

    })

    }


    以上的方法是网上搜索到的,我看了一下,其实很简单,就不上自己的代码了,直接copy下来。

    经我自己测试OK,问题已解决。

    展开全文
  • 重复ajax请求让人很受伤 重复ajax请求一波又一波的袭来,服务器正躲在角落里瑟瑟发抖,它内心是崩溃的,这算是遭了罪了, 前端小王子为啥没有做好限制和封锁,真是伤不起啊,哎,不如意事常八九,能与人言无二...

    重复的ajax请求让人很受伤

    重复的ajax请求一波又一波的袭来,服务器正躲在角落里瑟瑟发抖,它内心是崩溃的,这算是遭了罪了, 前端小王子为啥没有做好限制和封锁,真是伤不起啊,哎,不如意事常八九,能与人言无二三...... 以上场景是我们平时在开发中稍微不注意就会重现的,也因此伤了多少服务器的心;我们作为前端开发人员,应该正视而且重视这个问题。在这里,给大家提供以下几种解决方案:

    1. UI层面的拦截

    当用户动了动发财的小手点击完按钮后,就立即禁用按钮, 并开启等待动画,如果收到服务器的成功响应返回后,再隐藏动画,一定要设置超时,时间不能太长,如果过长,用户会骂街的。

    重复的ajax请求让人很受伤

     

    1.$("#submit").prop("disabled",true); //按钮禁用

    2.showLoading() //显示动画

    3.$.ajax({

    ...
    
        timeout: 4000,  // 设置超时时间
    
        complete:function(){
    
            hideLoading() //隐藏动画
    
        }
    
    })    

    2. JS层面的封锁

    (1) 暴力点击

    如果用户连续暴力点击按钮,我们可以通过函数防抖来做,其实就是闭包里的setTimeoutclearTimeout结合使用, 连续的点击会把上一次点击处理函数清掉,我们的 ajax请求会在最后一次点击后再发出去。

            obtn.onclick = (function(){
    
                var timer;
    
                return function(){
    
                    if(timer){
    
                       clearTimeout(timer)
    
                    }
    
                    timer= setTimeout(() => {
    
                        console.log("ajax发送; 查询结果")
    
                    }, 500)
    
                }
    
            })()

    (2)多tab页快速切换

    多个tab页 快速切换也是常见的场景,如果用户从tab1快速切换到tab2,再从tab2快速切换到tab1,不避免的同一个tab 要重复发起多次请求。

    还有一个问题就是,在单页面应用中,切换tab后dom 结构销毁了,此时数据回来了,如果去操作了已经销毁的dom,那么控制台会报错。而在vue ,react 等不需要开发者手动操作的dom的框架,如果我们去修改状态,还会报出如下的警告信息,这就很难看了。

    重复的ajax请求让人很受伤

     

    解决这个问题的思路就是abort掉上一个请求。XMLHttpRequest对象有abort方法,可以直接调用。

    如果使用第三方的请求库的话,比如axios,我们可以为我们的请求创建一个cancel token ,在每个请求设置一个token,在页面切换, 或者组件销毁前,只需要通过source.cancel取消就好了,其实原理还是通过xhr的abort方法实现。

    具体的代码以及流程可以参考如下。

    var CancelToken = axios.CancelToken;var source = CancelToken.source();​axios.get('/user/12345', {  cancelToken: source.token}).catch(function(thrown) {  if (axios.isCancel(thrown)) {    console.log('Request canceled', thrown.message);  } else {    // handle error  }});​// cancel the request (the message parameter is optional)source.cancel('Operation canceled by the user.');

    不同的使用场景,我们可以灵活的组合以上的解决方案, 不知道这样做的话,是否能挽回服务器的心,我又想起了夕阳下的奔跑,那是我与服务器美好邂逅,也是我们逝去的青春......

    展开全文
  • 防止ajax重复提交

    2019-08-01 14:37:18
    首先说说防止重复点击提交是什么意思。... 不妨引深来看,它不一定发生在表单的提交事件上,同样可以发生在ajax的异步请求上。有效地在web客户端采用一定机制去防止重复点击提交,将大大减轻服务器端压...

    首先说说防止重复点击提交是什么意思。

      我们在访问有的网站,输入表单完成以后,单击提交按钮进行提交以后,提交按钮就会变为灰色,用户不能再单击第二次,直到重新加载页面或者跳转。这样,可以一定程度上防止用户重复提交导致应用程序上逻辑错误。

      不妨引深来看,它不一定发生在表单的提交事件上,同样可以发生在ajax的异步请求上。有效地在web客户端采用一定机制去防止重复点击提交,将大大减轻服务器端压力。

      那么,我们就不妨从表单提交及ajax的两种不同请求的处理过程中,来试试如何防止重复点击提交。

      一、表单提交

      就以登录表单为例,代码如下:

     

    <form action="login.do" method="post">
        <input type="text" name="username" />
        <input type="password" name="password" />
        <input type="submit" οnclick="this.disabled=true; this.value='登录中...'; this.form.submit();" value="登录" />
    </form>

    单击登录按钮进行提交以后,提交按钮就会变为灰色,并且给用户一个友好提示(登录中...),用户不能再单击第二次,直到重新加载页面或者跳转。

      可以发现,我们不需要给这个按钮恢复到可以再次登录的状态,仅仅源于页面重新进行了加载或者跳转。

      但是,针对ajax的请求上,我们又该如何处理呢?

      二、ajax请求

    复制代码

     1 (function ($) {
     2     
     3     $('.J-login').click(function () {
     4     
     5         var loginBtn = this;
     6         
     7         //1.先进行表单验证
     8         //......
     9         
    10         //2.让提交按钮失效,以实现防止按钮重复点击
    11         $(loginBtn).attr('disabled', 'disabled');
    12         
    13         //3.给用户提供友好状态提示
    14         $(loginBtn).text('登录中...');
    15         
    16         //4.异步提交
    17         $.ajax({
    18             url: 'login.do',
    19             data: $(this).closest('form[name="loginForm"]').serialize(),
    20             type: 'post',
    21             success: function(msg){
    22                 
    23                 if (msg === 'ok') {
    24                     alert('登录成功!');
    25                     
    26                     //TODO 其他操作...
    27                 } else {
    28                     alert('登录失败,请重新登录!');
    29                     
    30                     //5.让登陆按钮重新有效
    31                     $(loginBtn).removeAttr('disabled');
    32                 }
    33     
    34             }
    35         });
    36         
    37     });
    38     
    39 })(jQuery);

    复制代码

    可以发现,当登录失败后,需要重新让登录按钮具有登录事件。

      当然,我们可以用一个更加优雅的方式来代替之。

    复制代码

     1 (function ($) {
     2     
     3     $('.J-login').click(function () {
     4     
     5         var loginBtn = this;
     6         
     7         //1.先进行表单验证
     8         //......
     9         
    10         //2.异步提交
    11         $.ajax({
    12             url: 'login.do',
    13             data: $(this).closest('form[name="loginForm"]').serialize(),
    14             type: 'post',
    15             beforeSend: function () {
    16                 //3.让提交按钮失效,以实现防止按钮重复点击
    17                 $(loginBtn).attr('disabled', 'disabled');
    18                 
    19                 //4.给用户提供友好状态提示
    20                 $(loginBtn).text('登录中...');
    21             },
    22             complete: function () {
    23                 //5.让登陆按钮重新有效
    24                 $(loginBtn).removeAttr('disabled');
    25             },
    26             success: function(msg){
    27                 
    28                 if (msg === 'ok') {
    29                     alert('登录成功!');
    30                     
    31                     //TODO 其他操作...
    32                 } else {
    33                     alert('登录失败,请重新登录!');
    34                 }
    35     
    36             }
    37         });
    38         
    39     });
    40     
    41 })(jQuery);

    复制代码

    在这里,我仅仅举了一个最为简单的例子,还有很多其他的方式进行防止重复点击提交,如

      1> 定义标志位:

        点击触发请求后,标志位为false量;请求(或者包括请求后具体的业务流程处理)后,标志位为true量。通过标志位来判断用户点击是否具备应有的响应。

      2> 卸载及重载绑定事件:

        点击触发请求后,卸载点击事件;请求(或者包括请求后具体的业务流程处理)后,重新载入绑定事件。

      3> 替换(移除)按钮DOM

        点击触发请求后,将按钮DOM对象替换掉(或者将之移除),自然而然此时不在具备点击事件;请求(或者包括请求后具体的业务流程处理)后,给新的按钮DOM定义点击事件。

      当然,还有其他的方式进行实现,欢迎各位博友补充。

      三、请求频度

      相信大家碰到过这样的业务,我们允许它重复点击(或者其他用户事件),但是不允许在一定的时间内超过次数XX次。这从用户友好体验及服务器承受压力选取了一个折中方案。

      最合适不过的例子,莫过于关键字搜索匹配了。

      相信大家定然首先想到节流函数了。

    复制代码

     1 var timer = null;
     2 
     3 $(input).keyup(function(){
     4     
     5     var value = $(this).val();
     6     
     7     clearTimeout(timer); 
     8       
     9     //如果键盘敲击速度太快,小于100毫秒的话就不会向后台发请求,但是最后总会进行一次请求的。
    10     timer = setTimeout(function() {
    11         //触发请求
    12         $.ajax({
    13             url: 'typeahead.do',
    14             type: 'get',
    15             data: value,
    16             success: function () {
    17                 //显示匹配结果
    18                 //......
    19             }
    20         });
    21     },100);
    22     
    23 });

    复制代码

    四、总结

      从宏观意义上来讲,我们需要对每一个按钮去做”防止重复点击提交“,面对这种情况,我们便可以采用一定策略来对其进行封装实现(如定义通用按钮类绑定事件)。

      从具体情况上来讲,我们并不需要对每一个按钮都去做”防止重复点击提交“,仅仅需要对某些可能具有复杂后台业务逻辑、或者文件上传、或者调用其他非本工程接口导致网络延迟等等情况需要去做”防止重复点击提交“。与此同时,我们必须要给予用户友好提示(如文本提示、渲染loading条、显示文件上传进度条等等)。两者需要一起来看、一起来做。当然,我们可以单独提取状态显示这个实现逻辑。代码如下——

    复制代码

     1 //全站ajax加载提示
     2 (function ($) {
     3 
     4     var str = '<div class="ajax-status" style="display: none;">'
     5             +    '<div class="ajax"><img src="' + publicPath + 'img/loading.gif" width="20" height="20" />数据加载中...</div>'
     6             +'</div>';
     7 
     8     var dom = $(str).prependTo('body');
     9 
    10     $(document).ajaxStart(function(){
    11         dom.stop(true,false).queue(function(){
    12             $(this).show().dequeue();
    13         });
    14     });
    15 
    16     $(document).ajaxStop(function(){
    17         dom.queue(function(){
    18             $(this).hide().dequeue();
    19         });
    20     });
    21 
    22 })(jQuery);

    复制代码

       总之,”防止重复点击提交“的应用场景及实现方式有很多,需要根据具体项目情况具体来定。

    展开全文
  • 在工作中有很多场景需要通过Ajax请求发送数据,像是注册、登录、提交...那,有没有办法解决重复发送请求的问题呢?从前端解决重复发送请求的方法是有的。1、点击“确定”之后禁用该按钮 var btn=$("#submit-btn");
  • 本篇内容开始介绍Ajax异步请求按钮在短时间内被重复点击,如何避免数据被覆盖的问题。经 过思考我们能够发现,解决这个问题的核心就是:保证一次请求的开始到结束的时间段内,按 钮不能在这个时间内再次发送请求。 ...
  • 第一:多次发送Ajax重复请求 由于系统使用Ajax请求时,没有对Ajax重复请求做处理,导致多次重复发送Ajax请求时,前台数据会出现重复加载的问题。 解决方案: 怎样防止重复发送 Ajax 请求? ...
  • ajax重复请求

    2019-03-07 18:07:20
    在实际应用中,我们会遇见这样的问题:使用ajax请求后台时,如果后台处理时间太长,那么我们前台可能会继续请求或者进行其他的请求操作,这样的话难免会发生数据错乱,所以我们就需要进行防重复请求操作,接下来就...
  • 优雅的ajax请求 [用disable防止重复请求]处理思路ajax简单介绍ajax参数(部分)ajax状态(部分)代码示例按钮部分代码ajax部分代码 在前后端交互的时候回经常用到ajax进行请求, 然而如果没有限制的话会造成一个请求发送...
  • 在同一个通用上传插件,每次都需要客户端去请求服务器,返回的html页面,如果请求的间隔很短的话,ajax会认为是重复作废的请求,这个时候需要修改一下源码来达到在短时间内重复请求也能得到响应 找到js/dwz.ajax....
  • 关于防止重复发送ajax请求,一般是重复点击提交按钮导致重复提交,网上也有很多解决方法,这里写一下我自己用的一个方法。 var postFlag = false; //定义一个变量为false function changeInfo(url,data) {  ...
  • 一、$.ajax为什么要再次封装 jquery很强大,基本js开发标准了,尔$.ajax做为异步加载数据功能也很强大,但有时却不能满足我们的需求,就需要再定制一下。 例如:添加数据时连点会产生多条数据,网络或程序出现问题...
  • 做一个项目,里面需要js 异步请求的时候,把上一次的的请求取消,由于使用的是jquery,挡在手册里没有找到关于.abort()方法,在网上搜索了一下,在http://ooxx.me/jquery-ajax-abort.orz看到有关于jquery 里.abort...
  • 开发过程中,发现jQuery中的ajax原本应该只发送一次请求,事实上却连续发送了多次。 解决办法是,在发送前作一个标记,检测是否已经发送过,成功或者失败再收回标记。 var th = $(this); $.ajax({ type: "GET...
  • JS通过ajax发起异步请求时,经常会出现一个按钮快速多次点击时,请求进行了多次提交,可能导致很多不必要的问题出现,比如写入某些脏数据等。  此处针对ajax发起请求多次提交的问题进行JS代码处理的简单方法有如下...
  • 页面发送ajax请求时,action会莫名其妙的执行两次,第一次请求时正常的,第二次请求是空. 解决方法: 1:Action类中业务方法避免使用get 和set开头. 2:使用注解@JSON(serialize=false) 例如: @JSON(serialize=false)//...
  • 虽然Jquery有自带的ajax,但是有时候页面可能也会用到一些别的ajax插件。 简单描述一下我的问题:可能和其他的ajax多次加载不太一样,进入第一次,加载一次,第二次进入,加载两次,第三次进入,加载三次。。。依次...
  • 1、第一种,对于onclick事件触发的的ajax可以采用如下方法: 即在beforeSend中使点击按钮不可用,ajax结果返回后置为可用 $.ajax( { type: 'POST', url: APP+'?m=Shopping&a=ajaxSubmitorder&sid='+sid+'&src='+...
  • 如图所示,点击按钮之后,完成请求,页面又会刷新至下面的链接(首页),上面的链接是请求页面,下面的连接是首页, 问题原因出在HTML文件上,原因是我把刚才所有的元素都放在了一个标志的表单里面了,里面的元素...
  • 解决struts2下ajax请求提交两次的问题 在使用struts2时候发现一个问题。 如果这个package继承了json-default的时候。如果在页面发送ajax请求的时候。在action中如果有多个方法的时候。会莫名其妙的发送了两个...
1 2 3 4 5 ... 20
收藏数 49,834
精华内容 19,933
关键字:

ajax重复请求