【问题标题】:Ajax sends multiple POSTs of single eventAjax 发送单个事件的多个 POST
【发布时间】:2016-08-23 04:25:27
【问题描述】:

是什么导致 ajax 同时发送多个 POST 请求?很难重现,因为它发生的概率约为 2%。它似乎发生在不良/移动网络上。我们在 Android 上使用 Chrome。

表单的工作原理

  • .keyup 事件监听器等待 N 个字符,然后通过 ajax 调用进行一些小的验证后从表单发送数据。
  • 立即清除表单,以便发送另一个请求。
  • onSuccess 返回并更新总计表。

问题 系统应该只保存一条记录时保存了多条记录。

我发现/尝试了什么

  • 只有一个调用返回到 UI。 onSuccess 仅在发生这种情况时调用一次。每当发生这种情况时,用户界面的总数就会不同步。
  • 双击还是双击?不,我创建了一个检查,以防止相同值的重复数据被背靠背发送。
  • 服务器访问日志同时显示重复请求。
  • 我认为这是由于 HTTP/1.1 RFC 8.2.4:它说可以重试 POST 请求,所以我对控制器进行了更改以检查时间戳 (p),但由于请求是在完全相同的时间,我的代码没有捕捉到相同的 p 正在通过。 https://stackoverflow.com/a/14345476/2537574

[22/Aug/2016:07:14:12 -0700] "POST /api/save?p=14718752538085 HTTP/1.1" 200 749
[22/Aug/2016:07:14:12 -0700]“POST /api/save?p=14718752538085 HTTP/1.1”200 736

尝试 6 - 无效

unbind/bind 是老方法。现在尝试使用 .off 和 .on 并添加了 e.preventDefault()。 (https://stackoverflow.com/a/14469041/2537574)

$(document).off('keyup', "#field").on('keyup',"#field" ,function(e) {
    e.preventDefault();
        ... 

尝试 7 - 无效return false 添加到 keyup 事件侦听器的末尾。

$(document).off('keyup', "#field").on('keyup',"#field" ,function(e) {
    e.preventDefault();
    // checks for 6 chars and submits
    return false;
)};

尝试 8 - 去抖动

$(document).off('keyup', "#field").on('keyup',"#field" ,debounce(function(e) {
    // checks for 6 chars and submits
},50));

尝试 9 - 更新网络服务器 Tomcat 更新到最新的 tomcat 7.70,但这并没有解决问题。

当前代码

$(document).off('keyup', "#field").on('keyup',"#field" ,debounce(function(e) {

        e.preventDefault(); // attempt 6
        if(e.which != 13){
            if($(this).val().length ==6){                   
                submitForm();                   
                $(this).val('');
            }
        }
        return false; // attempt 7
    },50)); 

    function submitForm(){
        // Does some validation and if it passes calls:
        persist();
    }

    function persist(){
        var data = $("#Form").serialize();
        var persistNum = Date.now()+''+(Math.floor(Math.random() * 9)); // used to prevent duplicate insertion on POST retry

        $.ajax({
            url: "/api/save?pNum="+persistNum,
            context:document.body,
            cache: false,
            type: "POST",
            data: data,
            success:function(data, textStatus, jqXHR){},
            error: function(jqXHR, textStatus, errorThrown) 
            {}
        });     
      }

【问题讨论】:

  • 可能是 shift/ctrl/alt/meta 键导致您出现问题吗?
  • 别这么认为,他们正在使用平板电脑。
  • 每次按键都调用Ajax?可能想要去抖动它
  • @epascarello 它只在 6 个字符后提交,但我会研究“去抖动”。谢谢!
  • @epascarello debounce 没有解决问题,但我会保留它,因为它是一种改进,谢谢。

标签: jquery ajax post duplicates tomcat7


【解决方案1】:

我不能确定这是你的问题,但你肯定想在使用它调用 ajax 时使用带 keyup 的计时器,以便它仅在用户停止输入时触发。另外,我会跟踪提交状态,只有在尚未发送时才发送。这是我使用的,它可以解决你的问题:

var ajaxProcessing = false; // keep track of submission state

$('#field').unbind('keyup').keyup(function(e) {
  if (ajaxProcessing) return; // if processing, ignore keyup
  var $this = $(this);
  keyupDelay(function() { // keyup timer, see below
    if (e.which != 13) {
      if ($this.val().trim().length == 6) { // good UX to trim the value here ;)
        submitForm();
      }
    }
  }, 500); // this sets it to go off .5 seconds after you stop typing. Change as needed

});

function submitForm() {
  // Does some validation and if it passes calls:
  persist();
}

function persist() {
  ajaxProcessing = true; // set is proccessing
  var data = $("#Form").serialize();
  $.ajax({
    url: "/api/save",
    context: document.body,
    cache: false,
    type: "POST",
    data: data,
    success: function(data, textStatus, jqXHR) {
      ajaxProcessing = false;
      $("#Form").find("input[type=text], textarea").val(""); // reset form here
    },
    error: function(jqXHR, textStatus, errorThrown) {
      ajaxProcessing = false;
      alert('Form was submitted. It failed though because ajax wont work from SO');
    }
  });
}



// keyup timer funtion
var keyupDelay = (function() {
  var timer = 0;
  return function(callback, ms) {
    clearTimeout(timer);
    timer = setTimeout(callback, ms);
  };
})();
input {
  width: 400px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="" id="Form">
  <input type="text" maxlength="6" placeholder="type 6 chars here then stop" id="field">
</form>

【讨论】:

  • 我不认为这会有所帮助,因为他们扫描了 6 个字符的条形码并且我在服务器上获取了所有 6 个字符,但我确实喜欢 keyupDelay 功能,我将使用它处理不良扫描。谢谢。
  • @Rio,我不确定我明白你在说什么。您的代码当前正在使用 $('#field').unbind('keyup').keyup(function (e) { 发送 ajax...对吗?
  • 是的,一旦它看到 6 个字符,它就会发送 ajax。用户实际上是在将条形码扫描到输入字段中,而不是打字。换句话说,扫描仪模拟人类键入数字。因为条形码只有 6 个字符,所以它总是停在 6 个字符处。所以,一旦我看到 str.length = 6,我就调用 submitForm()。感谢您的帮助。
  • @Rio 够公平的。上面对ajaxProcessing 的检查仍然会阻止来自客户端的任何重复提交。如果这不能阻止您的问题,则几乎可以肯定问题出在您的服务器端代码中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-23
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-27
相关资源
最近更新 更多