我将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上运行
答案 0 :(得分:1)
可能的原因如下::
允许缓存使用会话的请求:
无论何时在请求期间启动会话,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()
在Symfony 4.1中不建议使用不存在任何会话的Request :: getSession(),它将在Symfony 5.0中引发异常。解决方案是始终先使用Request :: hasSession()方法检查会话是否存在:
if ($request->hasSession() && ($session = $request->getSession())) {
$session->set('some_key', 'some_value');
}
有关参考文献的更多信息:Here。
答案 1 :(得分:1)
您是否已检查 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()
]);
start-without-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>
start-with-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>
我不是100%肯定这种情况。需要更多信息。
答案 2 :(得分:1)
好的,所以问题出在会话固定策略上,因为该策略正在更改每个请求和每个AJAX请求之间的会话ID,而确实有时间更新新ID。
解决方案非常简单,只需设置session_fixation_strategy: none
。
答案 3 :(得分:0)
当您的应用程序依赖实时cookie时,您不能同时启动所有AJAX请求。 也许symfony使用cookie中的某些内容来进行CSRF令牌工作。
请求之间的超时时间为100毫秒的原因是,第一个请求有时间来解析响应并使用该响应更改cookie,而下一个请求使用了新的cookie。
您需要做的是:
OR
OR