为什么此 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 变量的修复程序(可能甚至不是代码方面的,甚至可能是服务器设置)?
再现测试场景
- 删除域的所有 cookie
- 加载页面(最多 2 次)。重新加载 2 次后问题不再出现。
- 如果未显示错误结果,请重复步骤。
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."
)));
}
?>
每个请求:
阅读评论以获取更多信息
有两件事可能导致此问题。
- 您在会话保存路径 (df -h) 中没有足够的 space 或者您的服务器没有保存它的权限。
- 您的服务器位于负载均衡器之后,您必须将会话保存在持久性后端(例如 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 检查您的会话数据大小,可能超过了缓存大小。或者正在存储一些其他会话数据,耗尽您的缓存内存。增加缓存大小可能对您的情况有所帮助。
嗨,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 变量的修复程序(可能甚至不是代码方面的,甚至可能是服务器设置)?
再现测试场景
- 删除域的所有 cookie
- 加载页面(最多 2 次)。重新加载 2 次后问题不再出现。
- 如果未显示错误结果,请重复步骤。
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."
)));
}
?>
每个请求:
阅读评论以获取更多信息
有两件事可能导致此问题。
- 您在会话保存路径 (df -h) 中没有足够的 space 或者您的服务器没有保存它的权限。
- 您的服务器位于负载均衡器之后,您必须将会话保存在持久性后端(例如 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 检查您的会话数据大小,可能超过了缓存大小。或者正在存储一些其他会话数据,耗尽您的缓存内存。增加缓存大小可能对您的情况有所帮助。