为啥这个 PHP 脚本(由 AJAX 调用)随机无法正确加载 SESSION?
Posted
技术标签:
【中文标题】为啥这个 PHP 脚本(由 AJAX 调用)随机无法正确加载 SESSION?【英文标题】:Why does this PHP script (called by AJAX) randomly not load SESSION correctly?为什么这个 PHP 脚本(由 AJAX 调用)随机无法正确加载 SESSION? 【发布时间】:2015-09-20 17:21:14 【问题描述】:啊,堆栈溢出,
我在我的项目中遇到过这个问题:简而言之,根据我收集到的信息,通过 AJAX 调用的 php 脚本没有正确注册在 index.php
页面顶部设置的 SESSION 变量。起初,我认为这是由于会话锁定,所以我继续添加session_write_close()
,但是,这并没有解决问题。
此问题仅发生在大约 25% 的时间在新用户会话开始后(即:当用户登录时)。
我继续删除了 90% 的代码,以将错误降低到重现所需的最低编码。
Firebug 通过 ajax.php 产生的错误结果
Firebug 通过 ajax.php 得到的预期结果
注意:两个结果都显示索引的print_r($_SESSION)
返回为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."
)));
?>
每个请求:
阅读 cmets 了解更多信息
【问题讨论】:
进入控制台的网络选项卡,检查请求Cookies中是否发送PHPSESSID
。
我怀疑这是时间问题。您在浏览器加载 cookie 之前发送 AJAX 请求。
是的,好的和坏的结果都会发送PHPSESSID
cookie 值。由于它确实发送了会话 ID,我怀疑这是一个时间问题(尤其是因为主脚本在调用 ajax 之前等待用户交互)。
如果它发送cookie,它似乎发送了错误的会话ID,它指的是一个空会话。 PHPSESSID cookie 是否与 index.php
页面收到的内容匹配?
帮自己一个忙,不要重复使用这样的变量名。
【参考方案1】:
有两个原因会导致此问题。
-
您在会话保存路径 (df -h) 中没有足够的空间,或者您的服务器没有保存它的权限。
您的服务器位于负载平衡器后面,您必须将会话保存在持久性后端(如 memcache 或 redis)中。
【讨论】:
据我了解,负载均衡器如何影响不影响初始页面本身的 AJAX? @TurdPile 它可能确实会影响但您正在设置会话数据(在 index.php 中),然后执行print_r
。尝试在会话开始后放置print_r
,您可能会看到它发生(当然第一次它会是空的)。
@TurdPile 也有可能,在主应用程序中,他们正在使用持久后端(如 Jordi 提到的),所以你不应该直接使用 $_SESSION
。
@RicardoVelhote 你的意思是session_start
在session_write_close
之后再次出现?
@TurdPile 你能给我们提供一个服务器响应信息吗?我寻找一个自定义标题,如“X-”或任何类似的东西。【参考方案2】:
如果您正在运行负载平衡器,那么您必须确保您的服务器能够达到数据的共同点。默认情况下,PHP 将会话存储在本地文件系统中。如果您的负载均衡器将您从服务器 A 发送到不存在该文件的服务器 B,这将成为一个问题。您可以设置网络共享并确保所有 Web 服务器都使用该共享。所以你可以创建一个 NFS 共享,然后添加 session_save_path 或 set it within php.ini
session_save_path('/your/nfs/share/here');
另一个选项是write your own session handler,它将会话放入您的数据库。然后,您可以使用 memcached 之类的东西来存储会话,这样您就不会在每次读取会话数据时都敲击您的数据库。
【讨论】:
NFS 不支持所需的锁定,因此不应用于 PHP 会话存储 - ***.com/questions/12552955/… @Marki555 有趣的链接。我想看看它在比传统磁驱动器(即 AWS 预置 IOPS)更快的情况下运行得如何。这个问题差不多3岁了。而且我自己更喜欢 Memcached,但它对于低流量来说有点过分了。【参考方案3】:我所附的屏幕截图对于我运行的几乎所有 25-30 次运行都是相同的。 [1]:http://i.stack.imgur.com/MgLpS.jpg 检查您的会话数据大小,也许它超过了缓存大小。或一些其他会话数据正在存储耗尽您的缓存内存。增加您的缓存大小可能会对您的方案有所帮助。
【讨论】:
已经确定是负载均衡引起的。谢谢,不过以上是关于为啥这个 PHP 脚本(由 AJAX 调用)随机无法正确加载 SESSION?的主要内容,如果未能解决你的问题,请参考以下文章
为啥这个带有 shell_exec 调用的 PHP 脚本从 Windows 10 的命令行运行,而不是浏览器/本地主机?