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

2022-08-30 18:35:24

Ahoy StackOverflow,

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

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

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

Firebug 通过 ajax 的坏结果.php

图像

Firebug 通过 ajax 的预期结果.php

image2

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

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

繁殖测试方案

  1. 删除域的所有 Cookie
  2. 加载页面(最多 2 次)。重新加载 2 次后,问题永远不会发生。
  3. 如果未显示不良结果,请重复步骤。

索引.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>

阿贾克斯.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."
    )));
}
?>

每个请求:

phpinfo

阅读评论以获取更多信息


答案 1

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

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

答案 2

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

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

另一种选择是编写自己的会话处理程序,将会话放入数据库中。然后,您可以使用类似 memcached 之类的东西来存储会话,这样您就不会在每次读取会话数据时都锤击数据库。


推荐