我将Symfony应用程序从Symfony 4.0.7升级到Symfony 4.1,之后AJAX调用丢失了会话值。
我同时调用了大约6个ajax请求。其中第一个进展顺利,但其他人正在失去会话价值。它发生在迁移到Symfony 4.1之后,仅用于AJAX调用。有任何想法吗?
编辑:只有在同时调用ajax时才会发生。我在调用ajax之间添加例如100毫秒的延迟然后一切正常。
edit2:它发生在4个不同的服务器上。 2台dev服务器,1台测试服务器和1台实时服务器。所有这些都运行在NGINX和php7上
可能的原因可能如下::
允许缓存使用会话的请求:
每当在请求期间启动会话时,Symfony都会将响应转换为私有的非可缓存响应,以防止泄露私人信息。但是,即使在某些情况下也可以缓存使用会话的请求。
例如,可以为属于该组的所有用户缓存与某个用户组相关的信息。处理这些高级缓存方案超出了Symfony的范围,但可以使用FOSHttpCacheBundle解决它们。
为了禁用使用会话无法缓存的请求的默认Symfony行为,在Symfony 4.1中我们添加了可以添加到响应的NO_AUTO_CACHE_CONTROL_HEADER标头:
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');
弃用Request :: getSession()的一些用法
在没有会话时使用Request :: getSession()已在Symfony 4.1中弃用,它将在Symfony 5.0中引发异常。解决方案是始终首先检查Request :: hasSession()方法是否存在会话:
if ($request->hasSession() && ($session = $request->getSession())) {
$session->set('some_key', 'some_value');
}
更多关于Ref:Here。
你检查过XMLHttpRequest.withCredentials吗?
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
响应标题怎么样?
这些请求的会话ID是否相等?
http://php.net/manual/en/function.session-id.php
也许您需要在ajax请求之前设置会话cookie。
这是一个例子:
ajax.php
<?php
function getSessionIdentifier()
{
if (!session_id()) {
session_start();
}
if (!isset($_SESSION['identifier'])) {
$_SESSION['identifier'] = bin2hex(random_bytes(5));
}
return $_SESSION['identifier'];
}
echo json_encode([
'identifier' => getSessionIdentifier()
]);
启动无-session.php文件
<!DOCTYPE html>
<html>
<head><title>start without session</title></head>
<body>
<script>
let started;
const cookie = () => '[' + document.cookie + ']';
const track = () => {
started = started || (new Date()).getTime();
return ((new Date()).getTime() - started) + 'ms';
};
const send = (index) => {
const req = new XMLHttpRequest();
req.open('GET', '/ajax.php');
console.log(track(), 'send', index, cookie());
req.addEventListener("load", () => {
console.log(track(), 'receive', index, cookie(), req.responseText);
});
req.send();
}
document.cookie = "PHPSESSID=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
console.log(track(), 'begin', cookie());
const len1 = 5;
const len2 = 10;
Array.from({length: len1}).forEach((v, i) => send(i));
console.log(track(), 'delay');
Array.from({length: len2}).forEach((v, j) => window.setTimeout(() => send(j + len1), j * 10));
</script>
</body></html>
启动与-session.php文件
<?php
session_start();
$_SESSION['identifier'] = bin2hex(random_bytes(5));
?><!DOCTYPE html>
<html>
<head><title>start with session</title></head>
<body>
<script>
let started;
const cookie = () => '[' + document.cookie + ']';
const track = () => {
started = started || (new Date()).getTime();
return ((new Date()).getTime() - started) + 'ms';
};
const send = (index) => {
const req = new XMLHttpRequest();
req.open('GET', '/ajax.php');
console.log(track(), 'send', index, cookie());
req.addEventListener("load", () => {
console.log(track(), 'receive', index, cookie(), req.responseText);
});
req.send();
}
//
// document.cookie = "PHPSESSID=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
//
console.log(track(), 'begin', cookie());
const len1 = 5;
const len2 = 10;
Array.from({length: len1}).forEach((v, i) => send(i));
console.log(track(), 'delay');
Array.from({length: len2}).forEach((v, j) => window.setTimeout(() => send(j + len1), j * 10));
</script>
</body></html>
我不是百分百肯定这是同样的情况。需要更多信息。
好的,所以问题是因为会话固定策略正在改变会话ID,每个请求和AJAX请求都有时间更新新ID。
解决方案非常简单,只需设置session_fixation_strategy: none
即可。
当您的应用程序依赖于实时cookie时,您不能在同一时间启动所有AJAX请求。也许symfony使用cookie中的某些东西来完成CSRF令牌的工作。
它在请求之间100毫秒超时的原因是第一个有时间解析响应并使用该响应更改cookie,下一个请求使用新cookie。
你需要做的是:
要么
要么