Я обновил свое приложение Symfony с Symfony 4.0.7 до Symfony 4.1, и после этого вызовы AJAX теряют значения сеансов.
У меня одновременно вызывается около 6 запросов ajax. Первый из них работает нормально, но другие теряют значения сеанса. Это произошло только после перехода на Symfony 4.1 и только для вызовов AJAX. Любые идеи?
edit: Это происходит только с одновременным вызовом ajax. Когда я добавляю, например, задержку в 100 миллисекунд между вызовом ajax, все работает нормально.
edit2: это происходит на 4 разных серверах. 2 сервера разработки, 1 тестовый сервер и 1 рабочий сервер. все они работают на NGINX и php7
@Bananaapple Я обновил свой пост
Попробуйте запустить локальный php bin/console server:run, чтобы проверить, получаете ли вы его. Кроме того, поскольку это связано с JS, попробуйте его в разных браузерах.
Может это: symfony.com/blog/new-in-symfony-4-1-session-improvements
Случись со мной в Laravel. Я не знаю, как это исправить, но это происходит, скажем, вы выполняете запрос ajax, и перед завершением этого запроса ajax вы выполняете другой запрос ajax, и он возвращается перед первым запросом ajax, тогда, когда первый сеанс завершения запроса ajax также будет удален . поэтому мне пришлось подождать, чтобы отправить второй запрос ajax, пока не завершится первый
@Bananaapple тестировался в разных браузерах, эффект такой же
@Alex, а как это мне поможет? Я читал эти статьи много раз раньше, и ничего напрямую не связано с моей проблемой. Единственное, что мы можем узнать оттуда, они как-то изменили сеансы, и теперь у меня проблема.
@SupunPraneeth, как я уже сказал: он отлично работает на Symfony 4.0.7, так что это проблема текущей версии symfony, а не php в целом. Как я уже сказал ранее, он отлично работает, когда я добавляю задержку между AJAX, но мне нужно, чтобы эти AJAX запускались более реже одновременно.
@nospor, извините, если это не помогло, я подумал, вы могли бы хотя бы проверить, что весь ваш код имеет hasSession(). Очень странно, что не работает только в одно и то же время, похоже, у вас настроена дополнительная конфигурация для js. Как сделать вызов ajax?
Я чувствую, что это сработает в случае setTimeout( doAjaxCall, 0) - вероятно, это обходной путь для вас
Вызовы @Alex ajax - это действительно простые ajax-вызовы один за другим. Установка задержки для 0 не будет работать: как я сказал в своем первом посте работает только для больших задержек, таких как 100 мс, и это зависит от времени отклика, поэтому это не постоянное число, и это не обходной путь для моей ситуации
Хотя я терял его, это первая тема с описанием, которое соответствует моей проблеме. Я сделал еще немного тестов: stackoverflow.com/questions/53188446/…






Возможные причины могут быть следующими::
Allow to cache requests that use sessions:
Каждый раз, когда сеанс запускается во время запроса, 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');
Deprecate some uses of 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: Здесь.
К сожалению, добавление этой опции в ответ не решает проблему :(
Где в коде писать строку $response? Есть ли способ установить этот заголовок глобально?
Вы можете обратиться к этому URL: symfony.com/doc/current/introduction/…
Вы проверяли XMLHttpRequest.withCredentials?
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
А как насчет заголовков ответов?
Равны ли идентификаторы сеанса этих запросов?
http://php.net/manual/en/function.session-id.php
Возможно, вам нужно установить cookie сеанса перед запросом ajax.
Вот пример:
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.info(track(), 'send', index, cookie());
req.addEventListener("load", () => {
console.info(track(), 'receive', index, cookie(), req.responseText);
});
req.send();
}
document.cookie = "PHPSESSID=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
console.info(track(), 'begin', cookie());
const len1 = 5;
const len2 = 10;
Array.from({length: len1}).forEach((v, i) => send(i));
console.info(track(), 'delay');
Array.from({length: len2}).forEach((v, j) => window.setTimeout(() => send(j + len1), j * 10));
</script>
</body></html>начать с-сессией.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.info(track(), 'send', index, cookie());
req.addEventListener("load", () => {
console.info(track(), 'receive', index, cookie(), req.responseText);
});
req.send();
}
//
// document.cookie = "PHPSESSID=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
//
console.info(track(), 'begin', cookie());
const len1 = 5;
const len2 = 10;
Array.from({length: len1}).forEach((v, i) => send(i));
console.info(track(), 'delay');
Array.from({length: len2}).forEach((v, j) => window.setTimeout(() => send(j + len1), j * 10));
</script>
</body></html>Я не уверен на 100%, что это та же ситуация. нужна дополнительная информация.
Итак, вы предлагаете, чтобы, когда я отправляю ajax с задержками, файлы cookie отправляются автоматически, а когда я отправляю ajax точно так же, за исключением того, что я не делаю никаких задержек, мне нужно устанавливать файл cookie вручную?
В php session_start () автоматически устанавливает cookie с именем PHPSESSID. Этот файл cookie используется для идентификации сеанса.
XMLHttpRequest.withCredentials сообщает браузеру об отправке запроса ajax с этим файлом cookie сеанса.
Я знаю это. Вот почему я спрашиваю вас: так вы говорите, что, когда я отправляю ajax один за другим, мне нужно устанавливать его вручную? Потому что, как я уже говорил несколько раз раньше, когда я отправлял AJAX с задержками, все работает нормально, без дополнительных настроек.
нет. Я говорю, что вам нужно установить cookie сеанса перед всеми этими запросами ajax. И все эти запросы ajax отправляются с одним и тем же файлом cookie сеанса.
Итак, я спрашиваю, почему мне не нужно устанавливать это, когда я вызываю AJAX с задержками?
@nospor, подробнее в ответ добавил. Но я не уверен, что это такая же ситуация, как у вас. Нам нужна дополнительная информация.
Спасибо за обновление, Энтони. Я JQuery отправляю AJAX. Он автоматически отправляет файлы cookie с каждым запросом. Я все еще думаю, что это ошибка обновления Symfony, особенно в том, что в 4.1 они внесли некоторые изменения в сессию. С Symfony 4.0.7 этот немедленный ajax работает отлично. Я не меняю вызовы ajax. Я меняю версию SF, а потом она перестает работать.
Вы не должны запускать все запросы AJAX одновременно, когда ваше приложение зависит от живых файлов cookie. Возможно, Symfony использует что-то в файлах cookie для работы с токеном CSRF.
Причина, по которой он работал с тайм-аутом 100 мс между запросами, заключается в том, что у первого было время проанализировать ответ и изменить файлы cookie с этим ответом, а следующий запрос использовал новые файлы cookie.
что вам нужно сделать, это:
ИЛИ ЖЕ
ИЛИ ЖЕ
Простой вопрос: почему он работает с Symfony 4.0.7, а после обновления до Symfony 4.1 перестает работать? Для меня это ошибка Symfony, а не ajax.
ad1) Я не могу этого сделать. Эти вызовы ajax предназначены для данных диаграмм. Некоторые диаграммы могут быть созданы быстрее, чем другие. Я не могу создавать диаграмму за диаграммой, потому что отображение всех диаграмм может занять гораздо больше времени. ad2) Мне нужны эти недостающие данные для аутентификации. Я не могу их игнорировать. ad3) Да, это могло бы быть решением, но все же я думаю, что это ошибка обновления SF4.1, и я не хочу тратить время на внедрение JWT, когда он не нужен
ad1) загрузка диаграмм одну за другой из одной и той же установки Symfony выполняется быстрее, чем загрузка их всех сразу. делая это, вы также избегаете риска тайм-аута для одного из запросов ajax. Попробуйте сравнить два метода. вы будете удивлены результатами
С этим решением клиентам придется дольше ждать, чтобы увидеть графики. Идея состоит в том, что они могут увидеть некоторые "более быстрые" графики раньше, если это возможно, и это прекрасно работало для Sf 4.0.7.
Итак, проблема была из-за стратегии фиксации сеанса, которая изменяла идентификатор сеанса каждый запрос, а запросы AJAX каждый за другим имели время для обновления нового идентификатора.
Решение было довольно простым, достаточно установить session_fixation_strategy: none.
Это не постоянное решение, но пока работает для меня :)
@Martijn Рад, что смог немного помочь :)
Как я могу установить session_fixation_strategy: none ??
@Saurabh вам нужно установить его в файле security.yml session_fixation_strategy: none
@nospor: спасибо за ответ, я просмотрел документацию, и там написано «не рекомендуется». Почему? Сделало бы это уязвимым?
@nospor: у меня такая же ситуация, вот stackoverflow.com/questions/56255053/…
@Saurabh не рекомендуется, так как это менее безопасно. Тем не менее, для меня это работает, и на данный момент мне нужно это
На каком сервере вы испытываете это? Было бы интересно узнать, локальный ли это Symfony, apache или что-то еще. Было бы еще интереснее узнать, происходит ли это на разных экземплярах / настройках сервера, поскольку это указывало бы на конфигурацию сервера или symfony, на которую вам нужно смотреть ...