Ajax发送单个事件的多个POST [英] Ajax sends multiple POSTs of single event

查看:121
本文介绍了Ajax发送单个事件的多个POST的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么原因导致ajax同时发送多个POST请求?它很难再现,因为它发生在大约2%的时间。似乎在坏/移动网络上发生。我们在Android上使用Chrome。



表单的工作方式




  • .keyup事件监听器等待N个字符,然后通过ajax调用经过一些次要验证后从表单发送数据。

  • 表单立即清除,以便另一个请求可以

  • onSuccess返回并更新总计表。



问题
系统只能存储一个记录。



我发现/尝试了




  • 只有一个呼叫返回给用户界面。当这种情况发生时,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.1200 749 >
[22 / Aug / 2016:07:14:12 -0700]POST / api / save?p = 14718752538085 HTTP / 1.1200 736






没有工作



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


$ b $ ('keyup',#field,function(e){
($ key) e.preventDefault();
...

尝试7 - 没有工作
添加 return false 到keyup事件监听器的结束。

  $(document).off('keyup',#field)。 on('keyup','#field',function(e){
e.preventDefault();
//检查6个字符并提交
return false;
)};

尝试8 - 停用


$ b ('keyup',#field,debounce(function(e){
//检查6个字符并提交
},50));

尝试9 - 更新的Web服务器Tomcat
更新到最新tomcat 7.70但是没有解决问题。



当前代码



<$ p $ ('keyup','#field')。on('keyup','#field',debounce(function(e){

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

函数submitForm(){
//有一些验证,如果它通过调用:
persist();
}

函数persist(){
var data = $(#Form)。serialize();
var persistNum = Date.now()+''+(Math.floor(Math.random()* 9)); //用于防止重复插入POST重试

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


解决方案

我不能肯定这是你的问题,但是当你使用它来调用ajax时,肯定要使用带有keyup的计时器,这样当用户停止输入时才会触发。此外,我会跟踪提交状态,只有在没有发送的情况下才发送。这是我使用的,它可以解决你的问题:



  var ajaxProcessing = false; //跟踪提交状态$('#field')。unbind('keyup')。keyup(function(e){if(ajaxProcessing)return; //如果处理,忽略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); //这使它设置为关闭.5秒后你停止打字。根据需要更改}); function submitForm(){//进行一些验证,如果它通过调用: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被提交,但由于ajax不能从SO发起,所以失败);}});} // keyup timer funtionvar keyupDelay =(function(){var timer = 0; return function(callback,ms){clearTimeout定时器); 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 = 形式 > < input type =textmaxlength =6placeholder =type 6 chars here then stopid =field>< / form>  

/ div>


What causes ajax to send more than one POST request at the same time? It is hard to reproduce since it happens about 2% of the time. It seems to happen on bad/mobile networks. We are using Chrome on Android.

How Form Works

  • .keyup event listener waits for N characters and then sends the data from the form after some minor validation via an ajax call.
  • The form is immediately cleared so that another request can be sent.
  • onSuccess returns and updates a totals table.

Problem The system saves multiple records when it should only save one.

What I've found/tried

  • Only one call is returned to the UI. The onSuccess is only called once when this happens. The UI has a total that gets out of sync whenever this occurs.
  • Double scan or double click? No, I've created a check to prevent duplicate data of the same value to be sent back to back.
  • The server access logs show duplicate requests at the exact same time.
  • I thought it was due to HTTP/1.1 RFC 8.2.4: which says POST requests can be retried, so I made change to controller to check for a timestamp (p) but since the request is at the exact same time, my code does not catch that the same p is coming through. 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

Attempt 6 - Did not work

unbind/bind is the old way of doing it. Now trying to use .off and .on and added e.preventDefault(). (https://stackoverflow.com/a/14469041/2537574)

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

Attempt 7 - Did not work Added return false to end of keyup event listener.

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

Attempt 8 - Debounce

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

Attempt 9 - Updated web server Tomcat Updated to latest tomcat 7.70 but that did not fix the issue.

Current Code

$(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) 
            {}
        });     
      }

解决方案

I cant be certain this is your issue, but you definitely want to use a timer with keyup when using it to call ajax so that it only triggers when the user stops typing. Also, I would keep track of the submission state and only send if not already sending. This is what I use, and it may solve your problem:

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>

这篇关于Ajax发送单个事件的多个POST的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆