Ajax正在失去会话

时间:2018-06-19 09:43:06

标签: php symfony symfony4

我将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上运行

4 个答案:

答案 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

响应标题如何?

  1. Access-Control-Allow-Credentials:true
  2. 连接:保持活动状态
  3. set-cookie:...

这些请求的会话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>

enter image description here

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>

enter image description here

我不是100%肯定这种情况。需要更多信息。

答案 2 :(得分:1)

好的,所以问题出在会话固定策略上,因为该策略正在更改每个请求和每个AJAX请求之间的会话ID,而确实有时间更新新ID。

解决方案非常简单,只需设置session_fixation_strategy: none

答案 3 :(得分:0)

当您的应用程序依赖实时cookie时,您不能同时启动所有AJAX请求。 也许symfony使用cookie中的某些内容来进行CSRF令牌工作。

请求之间的超时时间为100毫秒的原因是,第一个请求有时间来解析响应并使用该响应更改cookie,而下一个请求使用了新的cookie。

您需要做的是:

  • 让第二个AJAX从第一个调用回调,第三个从第二个调用回调,依此类推...

OR

  • 找出cookie中需要更新的内容,以免产生错误并将其禁用。但是请注意,这种保护措施是有原因的,如果将其禁用,您可能会将应用程序暴露在安全漏洞之下。 如果您提供了错误的AJAX呼叫响应(inpect->浏览器中的网络),这可能有助于我们解决问题

OR

  • 使ajax调用使用基于JWT的中间件(如果您以前从未做过巫婆,那将很麻烦),因此它使用无状态会话。