两个ajax请求可能发生冲突?

Seb*_*idt 7 php ajax jquery zend-framework

我在我的一个网站上遇到问题,当网页加载时会执行两个ajax请求.我将jQuery与基于zend框架的PHP应用程序结合使用.

相关的HTML(简化)看起来像:

<select id="first">
     <option value="1">First Option</option>
     <option value="2">Second Option</option>
</select>
<div class="first_block"></div>

<select id="second">
     <option value="1">First Option</option>
     <option value="2">Second Option</option>
</select>
<div class="second_block"></div>
Run Code Online (Sandbox Code Playgroud)

这是我的jQuery的样子:

$(document).ready(function(){

// function to update the first block
var updateFirstBlock = function(){
    var param = $(this).val();
    $.ajax('module/controller/action/param/' + param, {
        'success': function(data){
            $('.first_block').html(data);
        }
    });
};

// bind and trigger the first update function
$('select#first').bind('change', updateFirstBlock );
$('select#first').trigger('change');


// function to update the second block
var updateSecondBlock = function(){
    var param= $(this).val();
    $.ajax('module/controller/another-action/param/' + param, {
        'success': function(data){
            $('.second_block').html(data);
        }
    });
};

// bind and trigger the second update function
$('select#second').bind('change', updateSecondBlock );
$('select#second').trigger('change');

});
Run Code Online (Sandbox Code Playgroud)

PHP应用程序只返回一些内容,这取决于分配的值.

现在加载页面时会发生什么,在十个案例中的九个案例中,两个请求中的一个没有得到答案.另一个得到200 OK了失败的一次.没有规律性,请求失败.

是否有可能在Web服务器(Apache 2.2)配置中出现问题,因此两个同时触发的请求相互约束?

编辑

如果我将两个请求async: false都设置为,则始终正确执行.所以我认为必定会发生碰撞.

编辑2

这种行为的一个可能原因可能是php的会话锁定.我会进一步研究这个问题.

Gar*_*een 1

看来你的 PHP 会话锁绝对是在正确的机架上:

会话锁定(并发)注意事项

默认的 PHP 会话模型会锁定会话,直到页面加载完成。因此,如果您有两到三个要加载的框架,并且每个框架都使用会话,那么它们将一次加载一个。这样一来,任何时候只有一个 PHP 执行上下文具有对会话的写访问权限。

session_write_close()有些人通过在完成向 写入任何数据后立即调用来解决此问题$_SESSION- 即使在调用后他们也可以继续读取数据。缺点是 session_write_close()您的代码仍然会锁定session_start()在任何会话页面上的第一次调用,并且您必须session_write_close()尽快在使用会话的任何地方进行操作。这仍然是一个非常好的方法,但是如果您的会话访问遵循某些特定模式,您可能有另一种需要较少修改代码的方法。

这个想法是,如果您的会话代码主要从会话中读取,很少写入会话,那么您可以允许并发访问。为了防止会话数据完全损坏,我们将在写入会话的后备存储(通常是 tmp 文件)时锁定它们。这意味着会话仅在我们写入后备存储的短暂时刻被锁定。但是,这意味着如果您同时加载两个页面,并且都修改会话,则最后一个获胜。无论哪个先加载,其数据都会被第二个加载的覆盖。如果您同意,您可以继续 - 否则,请使用上面的 session_write_close 方法。

如果您有一些复杂的代码,这些代码依赖于会话中的某些状态、数据库或文本文件中的某些状态或其他内容,那么您可能不想使用此方法。当您同时运行两个页面时,您可能会发现一个页面运行到一半,修改您的文本文件,然后第二个页面运行到底,进一步修改您的文本文件,然后第一个页面完成 - 您的数据可能是损坏,或者完全丢失。

因此,如果您准备调试潜在的非常非常讨厌的竞争条件,并且会话的访问模式是主要读取和很少写入(而不是大量写入),那么您可以尝试以下系统。

将 session_set_save_handler() 中的示例复制到包含文件中,位于启动会话的位置上方。修改会话write()方法:

function write($id, $sess_data)
{
  global $sess_save_path, $sess_session_name;

  $sess_file = "$sess_save_path/sess_$id";
  if ($fp = @fopen($sess_file, "w")) {
   flock($fp,LOCK_EX);
   $results=fwrite($fp, $sess_data);
   flock($fp,LOCK_UN);
   return($results);
  } else {
   return(false);
  }

}
Run Code Online (Sandbox Code Playgroud)

您可能还想为会话添加 GC(垃圾收集)方法。

当然,对这个建议持保留态度 - 我们目前在我们的测试服务器上运行它,并且似乎在那里工作正常,但是人们报告了共享内存会话处理程序的严重问题,并且此方法可能是那样不安全。

您还可以考虑为代码中可怕的并发敏感位实现自己的锁。

参考: http: //ch2.php.net/manual/en/ref.session.php#64525


实现数据库会话处理程序可能是值得的。使用数据库可以消除这个问题,如果使用良好的数据库结构,实际上可以稍微提高性能。