Ajax发送单个事件的多个POST

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

表单如何工作

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

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

我发现/尝试过的

  • 只有一个调用返回到UI。 只有在发生这种情况时才会调用onSuccess。 在发生这种情况时,UI的总数会不同步。
  • 双击还是双击? 不,我已经创建了一个检查,以防止将相同值的重复数据发送回来。
  • 服务器访问日志在同一时间显示重复的请求。
  • 我认为这是由于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

  • 事件绑定问题? 我做了这个改变: https : //stackoverflow.com/a/13475122/2537574 $(’#field’)。unbind(’keyup’)。keyup(function(e){

  • 事件冒泡问题? 我添加了这个: https: //stackoverflow.com/a/12708948/2537574 e.stopImmediatePropagation();

尝试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 – 没有工作添加返回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 – 更新的Web服务器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) {} }); } 

我不能确定这是你的问题,但你肯定想在使用它来调用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; }