أياكس يخسر الجلسات

5

لقد قمت بترقية تطبيق Symfony الخاص بي من Symfony 4.0.7 إلى Symfony 4.1 وبعد ذلك تفقد مكالمات AJAX قيم الجلسات.

لدي حوالي 6 طلبات أجاكس تسمى في نفس الوقت. أولهم يسير على ما يرام لكن الآخرين يفقدون قيم الجلسة. حدث ذلك فقط بعد الترحيل إلى Symfony 4.1 وفقط لمكالمات AJAX. أيه أفكار؟

تحرير: يحدث فقط مع اياكس دعا في نفس الوقت. عندما أضيف على سبيل المثال تأخير 100 ميلي ثانية بين استدعاء أجاكس ثم كل شيء يعمل بشكل جيد.

edit2: يحدث على 4 خوادم مختلفة. خادمان مطوران ، خادم اختبار واحد وخادم مباشر. جميعها تعمل على NGINX و php7

4 الاجابة

1
افضل جواب

حسنًا ، كانت المشكلة بسبب إستراتيجية تثبيت الجلسة التي كانت تغير معرّف الجلسة لكل طلب وطلبات AJAX كل بعد أخرى لديها الوقت لتحديث المعرّف الجديد.

كان الحل بسيطًا للغاية ، فقط حدد session_fixation_strategy: none .

:مؤلف
1
افضل جواب

هل راجعت XMLHttpRequest.withCredentials ؟

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

ماذا عن رؤوس الاستجابة؟

  1. Access-Control-Allow-Credentials: true
  2. اتصال: إبقاء على قيد الحياة
  3. تعيين ملف تعريف الارتباط: ...

هل معرف جلسة هذه الطلبات متساوٍ؟

http://php.net/manual/en/function.session-id.php

ربما تحتاج إلى تعيين ملف تعريف ارتباط الجلسة قبل طلب 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()
]);

بدء بدون جلسة. 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>

Imagen 699068

بدء بـ 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>

Imagen 699069

لست متأكدًا بنسبة 100٪ أن هذا هو نفس الوضع. بحاجة الى مزيد من المعلومات.

:مؤلف
1
افضل جواب

يمكن أن تكون الأسباب المحتملة على النحو التالي :

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');
}

المزيد عن المرجع: Here .

:مؤلف
0

يجب عليك عدم تشغيل جميع طلبات AJAX في نفس الوقت الذي يعتمد فيه تطبيقك على ملفات تعريف الارتباط الحية. ربما يستخدم symfony شيئًا في ملفات تعريف الارتباط للقيام بعمل CSRF Token.

السبب في أنها عملت مع مهلة 100 مللي ثانية بين الطلب هو أن الأول كان لديه الوقت لتحليل الاستجابة وتغيير ملفات تعريف الارتباط مع تلك الاستجابة ، واستخدم الطلب التالي ملفات تعريف الارتباط الجديدة.

ما عليك القيام به هو:

  • جعل مكالمة AJAX الثانية مكالمة هاتفية من الأولى ، والثالثة مكالمة هاتفية من الثانية وهكذا ...

أو

  • اكتشف ما يوجد في ملفات تعريف الارتباط التي تحتاج إلى تحديث حتى لا تولد خطأ وتعطيله. ولكن ضع في اعتبارك أن هذه الحماية سارية لسبب ما وقد تعرّض تطبيقك لخرق أمني إذا تم تعطيله. قد يساعدنا ذلك في تحديد المشكلة إذا قدمت ردود مكالمات AJAX الخاطئة (inpect-> network in browser)

أو

  • اجعل مكالمة ajax تستخدم وسيطًا قائمًا على JWT (الساحرة معقدة إذا لم تقم بذلك من قبل) لذلك تستخدم جلسة بدون حالة.
:مؤلف

أسئلة ذات صلة

فوق
قائمة طعام