Ajax теряет сеансы

Я обновил свое приложение 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

На каком сервере вы испытываете это? Было бы интересно узнать, локальный ли это Symfony, apache или что-то еще. Было бы еще интереснее узнать, происходит ли это на разных экземплярах / настройках сервера, поскольку это указывало бы на конфигурацию сервера или symfony, на которую вам нужно смотреть ...

Bananaapple 22.06.2018 10:01

@Bananaapple Я обновил свой пост

nospor 22.06.2018 13:13

Попробуйте запустить локальный php bin/console server:run, чтобы проверить, получаете ли вы его. Кроме того, поскольку это связано с JS, попробуйте его в разных браузерах.

Bananaapple 22.06.2018 14:30

Может это: symfony.com/blog/new-in-symfony-4-1-session-improvements

Alex 23.06.2018 09:35

Случись со мной в Laravel. Я не знаю, как это исправить, но это происходит, скажем, вы выполняете запрос ajax, и перед завершением этого запроса ajax вы выполняете другой запрос ajax, и он возвращается перед первым запросом ajax, тогда, когда первый сеанс завершения запроса ajax также будет удален . поэтому мне пришлось подождать, чтобы отправить второй запрос ajax, пока не завершится первый

Supun Praneeth 23.06.2018 10:21

@Bananaapple тестировался в разных браузерах, эффект такой же

nospor 25.06.2018 10:38

@Alex, а как это мне поможет? Я читал эти статьи много раз раньше, и ничего напрямую не связано с моей проблемой. Единственное, что мы можем узнать оттуда, они как-то изменили сеансы, и теперь у меня проблема.

nospor 25.06.2018 10:39

@SupunPraneeth, как я уже сказал: он отлично работает на Symfony 4.0.7, так что это проблема текущей версии symfony, а не php в целом. Как я уже сказал ранее, он отлично работает, когда я добавляю задержку между AJAX, но мне нужно, чтобы эти AJAX запускались более реже одновременно.

nospor 25.06.2018 10:41

@nospor, извините, если это не помогло, я подумал, вы могли бы хотя бы проверить, что весь ваш код имеет hasSession(). Очень странно, что не работает только в одно и то же время, похоже, у вас настроена дополнительная конфигурация для js. Как сделать вызов ajax?

Alex 25.06.2018 12:20

Я чувствую, что это сработает в случае setTimeout( doAjaxCall, 0) - вероятно, это обходной путь для вас

Alex 25.06.2018 12:21

Вызовы @Alex ajax - это действительно простые ajax-вызовы один за другим. Установка задержки для 0 не будет работать: как я сказал в своем первом посте работает только для больших задержек, таких как 100 мс, и это зависит от времени отклика, поэтому это не постоянное число, и это не обходной путь для моей ситуации

nospor 25.06.2018 12:40

Хотя я терял его, это первая тема с описанием, которое соответствует моей проблеме. Я сделал еще немного тестов: stackoverflow.com/questions/53188446/…

Martijn 13.11.2018 11:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
5
12
1 606
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Возможные причины могут быть следующими::

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: Здесь.

К сожалению, добавление этой опции в ответ не решает проблему :(

nospor 25.06.2018 10:34

Где в коде писать строку $response? Есть ли способ установить этот заголовок глобально?

Aurelien Stride 11.06.2020 13:18

Вы можете обратиться к этому URL: symfony.com/doc/current/introduction/…

Amit Verma 11.06.2020 14:19

Вы проверяли XMLHttpRequest.withCredentials?

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

А как насчет заголовков ответов?

  1. Access-Control-Allow-Credentials: правда
  2. Подключение: keep-alive
  3. установить cookie: ...

Равны ли идентификаторы сеанса этих запросов?

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 вручную?

nospor 27.06.2018 12:38

В php session_start () автоматически устанавливает cookie с именем PHPSESSID. Этот файл cookie используется для идентификации сеанса.

Anthony Zhan 27.06.2018 13:01

XMLHttpRequest.withCredentials сообщает браузеру об отправке запроса ajax с этим файлом cookie сеанса.

Anthony Zhan 27.06.2018 13:04

Я знаю это. Вот почему я спрашиваю вас: так вы говорите, что, когда я отправляю ajax один за другим, мне нужно устанавливать его вручную? Потому что, как я уже говорил несколько раз раньше, когда я отправлял AJAX с задержками, все работает нормально, без дополнительных настроек.

nospor 27.06.2018 13:11

нет. Я говорю, что вам нужно установить cookie сеанса перед всеми этими запросами ajax. И все эти запросы ajax отправляются с одним и тем же файлом cookie сеанса.

Anthony Zhan 27.06.2018 13:21

Итак, я спрашиваю, почему мне не нужно устанавливать это, когда я вызываю AJAX с задержками?

nospor 27.06.2018 14:30

@nospor, подробнее в ответ добавил. Но я не уверен, что это такая же ситуация, как у вас. Нам нужна дополнительная информация.

Anthony Zhan 28.06.2018 07:53

Спасибо за обновление, Энтони. Я JQuery отправляю AJAX. Он автоматически отправляет файлы cookie с каждым запросом. Я все еще думаю, что это ошибка обновления Symfony, особенно в том, что в 4.1 они внесли некоторые изменения в сессию. С Symfony 4.0.7 этот немедленный ajax работает отлично. Я не меняю вызовы ajax. Я меняю версию SF, а потом она перестает работать.

nospor 28.06.2018 16:26

Вы не должны запускать все запросы AJAX одновременно, когда ваше приложение зависит от живых файлов cookie. Возможно, Symfony использует что-то в файлах cookie для работы с токеном CSRF.

Причина, по которой он работал с тайм-аутом 100 мс между запросами, заключается в том, что у первого было время проанализировать ответ и изменить файлы cookie с этим ответом, а следующий запрос использовал новые файлы cookie.

что вам нужно сделать, это:

  • сделайте второй вызов AJAX обратным вызовом из первого, третий - обратным вызовом из второго и так далее ...

ИЛИ ЖЕ

  • узнать, что содержится в файлах cookie, которые должны быть актуальными, чтобы не генерировать ошибку, и отключить их. Но примите во внимание, что эта защита действует по определенной причине, и вы можете подвергнуть свое приложение нарушению безопасности, если она отключена. это может помочь нам решить проблему, если вы предоставите ответы на ошибочные вызовы AJAX (inpect-> network в браузере)

ИЛИ ЖЕ

  • Сделайте так, чтобы ваш вызов ajax использовал промежуточное ПО на основе JWT (это сложно, если вы никогда не делали этого раньше), поэтому он использует сеанс без сохранения состояния.

Простой вопрос: почему он работает с Symfony 4.0.7, а после обновления до Symfony 4.1 перестает работать? Для меня это ошибка Symfony, а не ajax.

nospor 28.06.2018 16:15

ad1) Я не могу этого сделать. Эти вызовы ajax предназначены для данных диаграмм. Некоторые диаграммы могут быть созданы быстрее, чем другие. Я не могу создавать диаграмму за диаграммой, потому что отображение всех диаграмм может занять гораздо больше времени. ad2) Мне нужны эти недостающие данные для аутентификации. Я не могу их игнорировать. ad3) Да, это могло бы быть решением, но все же я думаю, что это ошибка обновления SF4.1, и я не хочу тратить время на внедрение JWT, когда он не нужен

nospor 28.06.2018 16:29

ad1) загрузка диаграмм одну за другой из одной и той же установки Symfony выполняется быстрее, чем загрузка их всех сразу. делая это, вы также избегаете риска тайм-аута для одного из запросов ajax. Попробуйте сравнить два метода. вы будете удивлены результатами

N69S 29.06.2018 15:33

С этим решением клиентам придется дольше ждать, чтобы увидеть графики. Идея состоит в том, что они могут увидеть некоторые "более быстрые" графики раньше, если это возможно, и это прекрасно работало для Sf 4.0.7.

nospor 02.07.2018 15:39
Ответ принят как подходящий

Итак, проблема была из-за стратегии фиксации сеанса, которая изменяла идентификатор сеанса каждый запрос, а запросы AJAX каждый за другим имели время для обновления нового идентификатора.

Решение было довольно простым, достаточно установить session_fixation_strategy: none.

Это не постоянное решение, но пока работает для меня :)

Martijn 13.11.2018 11:16

@Martijn Рад, что смог немного помочь :)

nospor 13.11.2018 15:55

Как я могу установить session_fixation_strategy: none ??

Saurabh 22.05.2019 09:30

@Saurabh вам нужно установить его в файле security.yml session_fixation_strategy: none

nospor 22.05.2019 13:08

@nospor: спасибо за ответ, я просмотрел документацию, и там написано «не рекомендуется». Почему? Сделало бы это уязвимым?

Saurabh 22.05.2019 13:16

@nospor: у меня такая же ситуация, вот stackoverflow.com/questions/56255053/…

Saurabh 22.05.2019 13:17

@Saurabh не рекомендуется, так как это менее безопасно. Тем не менее, для меня это работает, и на данный момент мне нужно это

nospor 22.05.2019 14:40

Другие вопросы по теме