为什么此 PHP 脚本(由 AJAX 调用)随机无法正确加载 SESSION?

Why does this PHP script (called by AJAX) randomly not load SESSION correctly?

嗨,Whosebug,

我在我的项目中遇到过这个问题:简而言之,根据我收集到的信息,通过 AJAX 调用的 PHP 脚本没有正确注册已设置的 SESSION 变量在 index.php 页面的顶部。起初,我认为这是由于会话锁定,所以我继续添加 session_write_close(),但是,这并没有解决问题。

此问题仅在 新用户会话开始后(即:当用户登录时)约 25% 的时间发生。

我继续删除了 90% 的代码,将错误减少到重现所需的最低限度编码。

来自 Firebug 通过 ajax.php

的错误结果

Firebug 通过 ajax.php

的预期结果

注意:两个结果都将索引 print_r($_SESSION) 的 return 显示为 Array ( [userid] => 3724 [trialstatus] => 1 [trialtcompletions] => 0 [userlevel] => 5 ),这让我知道问题不在于在索引页面上设置的会话。

有谁知道可以正确允许通过 AJAX 调用的脚本正确访问 Session 变量的修复程序(可能甚至不是代码方面的,甚至可能是服务器设置)?

再现测试场景

  1. 删除域的所有 cookie
  2. 加载页面(最多 2 次)。重新加载 2 次后问题不再出现。
  3. 如果未显示错误结果,请重复步骤。

index.php

<?php

if (session_status() === PHP_SESSION_NONE) session_start();

if (!isset($_SESSION['userid']))
{
    $_SESSION['userid'] = 3724; //$login['AccountID'];
}

$_SESSION['trialstatus'] = "12";
$_SESSION['trialtcompletions'] = "12";
$_SESSION['userlevel'] = "12";
session_write_close();

print_r($_SESSION);
?>
<!DOCTYPE html><html><head><script src="./js/jquery.min.js"></script>
<script>
    function loadStage(step,input,callback){
        $.ajax({
            type: "POST",
            url: "./ajax.php",
            data: { step: step, input: input },
            dataType: "JSON",
            timeout: 5000,
            success: function(data){
                if(data !== false){
                    callback(data);
                }
            }
        });
    }

    $(document).ready(function(){
        startLoadingSequence();
    });

    function startLoadingSequence(skipped){
        loadStage(1,skipped,function(data){});
    }
</script>
</head></html>

ajax.php

<?php
if (session_status() === PHP_SESSION_NONE) session_start();

print_r($_SESSION);

if (!isset($_SESSION['userid']))
{
    die(json_encode(array(
        "error",
        "You must be logged in to view report data."
    )));
}
?>

每个请求:

阅读评论以获取更多信息

有两件事可能导致此问题。

  1. 您在会话保存路径 (df -h) 中没有足够的 space 或者您的服务器没有保存它的权限。
  2. 您的服务器位于负载均衡器之后,您必须将会话保存在持久性后端(例如 memcache 或 redis)中。

如果您是 运行 负载平衡器,那么您必须确保您的服务器访问数据的公共点。默认情况下 PHP 将会话存储在本地文件系统中。如果您的负载均衡器将您从服务器 A 发送到服务器 B,而该文件不存在,那将成为一个问题。您可以设置网络共享并确保所有 Web 服务器都使用该共享。所以你可以创建一个 NFS 共享,然后添加 session_save_path or set it within php.ini

session_save_path('/your/nfs/share/here');

另一种选择是 write your own session handler,它将会话放入您的数据库中。然后,您可以使用像 memcached 这样的东西来存储会话,这样您就不会在每次读取会话数据时都破坏数据库。

我附上的屏幕截图对于我 运行 的几乎所有 25-30 运行 都是相同的。 [1]: http://i.stack.imgur.com/MgLpS.jpg 检查您的会话数据大小,可能超过了缓存大小。或者正在存储一些其他会话数据,耗尽您的缓存内存。增加缓存大小可能对您的情况有所帮助。