zoukankan      html  css  js  c++  java
  • 一道面试题:如何防止异步请求的重复提交

    11月14日更新:

    首先谢谢大家对这个问题的讨论,为了后来的童鞋方便浏览,我结合大家的论文,重新补充编辑此贴,为标蓝色加粗字体部分。

    今天面试时考官问了一道题,以下是大致的回忆:

    问题大意: 如果点击一个按钮发送异步请求,如何防止短时间内用户重复提交,从而造成数据覆盖等问题:

    我回答的解决方法有:

    1. 提交后disable掉按钮,再次点击文本框时enable按钮

     (11月14号更新:

    提交后disable按钮是常用方法,

    外观表现上有:1. disable 按钮,在按钮上显示提交中等信息

                         2. 设置遮罩层,遮罩层上显示提交信息。

    在代码处理逻辑上是:

                         第一步: 设置开关变量。

           第二步: 提交前关掉按钮

                         第三步: 在回调函数中打开按钮

                       

    var isQuery = false;
    function query() {
        if (!isQuery) {
            $.ajax({
                beforeSend: function() {
                    isQuery = true
                },
                success: function() {
                    isQuery = false
                },
                error: function() {
                    isQuery = false;
                    return;
                }
            })
        } else {
            alert("waiting!!!");
        }
    }

    以下一段文字仅是补充当时的场景,disable 按钮的方式看上面代码即可,以下可忽略  : )

    上文中 ”再次点击文本框时enable 按钮使“ 不是disable 方法的一部分,只是为了补充 用开关变量disable按钮的思路可能存在一个问题:如果服务器端处理时间很长,甚至是服务器端挂掉了,一直在等超时的期间客户没法再次输入,因此设置了 再次点击文本框时enable 按钮 )

    面试官追问,那么如果用户还是快速地点击文本框,还是能快速地提交,

    2. 我想到了设置一个缓冲时间,例如200ms,200ms内的重复请求忽略,只执行最后一次的请求。

    这个方法的代码:

    var timer = null;
    btn.addEventListener('click', function () {
        if (typeof timer === 'number') {
            clearTimeout(timer);
        }
        timer = setTimeout(function () {
            //添加提交按钮的事件处理
        }, 200);
    }, false);

    我说这会影响到所有的用户的每次请求都有延迟,然后继续想:

    3. 所以想到提交后disable,然后settimeinterval,每隔一定时间,例如一秒钟,如果是disable的话那么enable 

    ( 其实这是在尝试解决上面提到的如果服务器端处理时间特别长,用户想重新输入的问题。

    PS: 因为是面试,我这里是为复述整个故事,其他童鞋可以忽略这段 )

    面试官指出,那么这个计时器就一直需要在运行咯,是啊,这样也是在消耗, (正在写博客的时候我在想能否设置一个计数器,如果连续好几次都是disable状态的话,可以移除定时器)

    于是继续想:

    4. 我想对每个异步请求判断下IP,如果是短时间内快速的重复提交,设定一个阈值,超过则判断为spam,把ip地址ban掉或者忽略请求,但这个缺陷是对每一个请求都进行了额外操作。

    然后面试官说这要后端配合,如果是前端呢?

    5. 我想到了设置hash值,发异步请求时带上一个hash值,如果服务器端在处理上一个请求还没有完成时又来了新请求,那么可以丢弃,继续等待返回,这样不会覆盖数据。

    然后发现,有走到需要后端配合了,面试官继续问,如果不要后端配合,如果仅仅是前端怎么做,

    6. 我只好想到发送异步请求时候带上时间戳/hash值,返回数据的时候也带上时间戳/hash值,然后看是不是最近发送的那个请求,是则渲染,否则丢弃。

    但是面试官在问有没有更好的方法,

    我当时如实告诉面试官想不出来了,很抱歉,

    刚才我看了下 xhr 对象的 API,发现有 abort() 方法,能立即取消请求,这个当然方便,每次保留上一次提交的xhr对象引用,下次点击时先abort() 上一个xhr请求,再重新发送请求,但是当时不知道这个方法,其实自己有想到是不是 xhr对象直接有取消请求的方法,但转而一想面试不可能这么简单吧,然后我不确定这个方法是否存在。所以没回答这个方法。

    (abort()  方法取消当前响应,关闭连接并且结束任何未决的网络活动。

    这个方法把 XMLHttpRequest 对象重置为 readyState 为 0 的状态,并且取消所有未决的网络活动。例如,如果请求用了太长时间,而且响应不再必要的时候,可以调用这个方法。请见: http://www.w3school.com.cn/xmldom/dom_http.asp

    )

    11月20日更新:感谢面试官,虽然面试挂了,还能有机会再次沟通,得知 abort()方法其实是当时面试官心里期待的回答,那个滚动条优化,面试官期待的是 throttle函数,再次感谢。

    当然不知道面试官希望我能回答出来的更好方法是什么,所以请有看到的朋友能不吝赐教,谢谢。

  • 相关阅读:
    MFC常用数据类型
    第四章 菜单、工具栏和状态栏(第8课)
    Bugku-CTF之文件包含2 (150)
    Bugku-CTF之本地包含( 60)
    Bugku-CTF之前女友(SKCTF)
    《Web安全攻防 渗透测试实战指南》 学习笔记 (四)
    Nmap工具用法详解
    《Web安全攻防 渗透测试实战指南 》 学习笔记 (三)
    《Web安全攻防 渗透测试实战指南》 学习笔记 (二)
    Bugku-CTF之PHP_encrypt_1(ISCCCTF) [fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=]
  • 原文地址:https://www.cnblogs.com/zztt/p/4093884.html
Copyright © 2011-2022 走看看