Skip to content

8. مثال [nuxt-05]: استمرارية المخزن باستخدام ملف تعريف ارتباط للجلسة

الهدف: نريد ألا يتم إعادة تعيين المخزن [Vuex] عند كل طلب إلى الخادم. للقيام بذلك، سنستخدم ملف تعريف ارتباط للجلسة:

  • سيتم تهيئة المخزن بواسطة الخادم ووضعه في ملف تعريف ارتباط للجلسة؛
  • سيتلقى متصفح العميل ملف تعريف الارتباط هذا وسيقوم بإرساله تلقائيًا مع كل طلب جديد إلى الخادم؛
  • سيتمكن الخادم عندئذٍ من استرداد ملف تعريف الارتباط هذا والعمل مع المخزن الذي يحتوي عليه، وهو مخزن تم تحديثه من قبل العميل؛

8.1. Présentation

يتم الحصول على المشروع [nuxt-05] في البداية عن طريق نسخ المشروع [nuxt-04]:

Image

سنرى أن الملف [store / index.js] هو الوحيد الذي سيتغير.

لاستخدام ملفات تعريف الارتباط مع [nuxt]، سنستخدم الوحدة النمطية [cookie-universal-nuxt] التي نقوم بتثبيتها مع [yarn] في محطة طرفية VSCode:

Image

  • في [4]، نكتب الأمر [yarn add cookie-universal-nuxt

وبذلك يتم إضافة وحدة نمطية جديدة إلى الملف [package.json] الخاص بالمشروع [dvp]:


...
},
  "dependencies": {
    "@nuxtjs/axios": "^5.3.6",
    "bootstrap": "^4.1.3",
    "bootstrap-vue": "^2.0.0",
    "cookie-universal-nuxt": "^2.0.19",
    "nuxt": "^2.0.0"
},

8.2. ملف التكوين [nuxt.config.js]

لكي يتمكن [nuxt] من استخدام ملفات تعريف الارتباط الخاصة بـ [cookie-universal-nuxt]، يجب الإعلان عن هذه الوحدة في ملف التكوين [nuxt.config.js]:


...
],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // الوثيقة: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // الوثيقة: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    // https://www.npmjs.com/package/cookie-universal-nuxt
    'cookie-universal-nuxt'
  ],
...

  • السطر 12، تمت إضافة الوحدة النمطية [cookie-universal-nuxt] إلى جدول الوحدات النمطية [6] الخاص بـ [nuxt

يصبح ملف [nuxt.config.js] في النهاية كما يلي:


export default {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  head: {
    title: 'Introduction à [nuxt.js]',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content: 'ssr routing loading asyncdata middleware plugins store'
      }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
  },
  /*
   ** Customize the progress-bar color
   */
  loading: { color: '#fff' },
  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // الوثيقة: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // الوثيقة: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt'،
    // الوثيقة: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios،
    // https://www.npmjs.com/package/cookie-universal-nuxt
    'cookie-universal-nuxt'
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {},
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  },
  // مجلد شفرة المصدر
  srcDir: 'nuxt-05',
  // الموجه
  router: {
    // جذر URL للتطبيق
    base: '/nuxt-05/'
  },
  // الخادم
  server: {
    // منفذ الخدمة، 3000 افتراضيًا
    port: 81,
    // عناوين الشبكة المستمعة، افتراضيًا localhost: 127.0.0.1
    // 0.0.0.0 = جميع عناوين الشبكة الخاصة بالجهاز
    host: 'localhost'
  },
  // البيئة
  env: {
    maxAge: 60 * 5
  }
}
  • السطر 79: تمت إضافة المفتاح [env] إلى الملف. هذا المفتاح هو كلمة محجوزة. العناصر المعلنة في هذا الكائن متاحة من الكائن [context.env] في عناصر التطبيق؛
  • السطر 80: سيكون السمة [maxAge] هي المدة القصوى لملف تعريف الارتباط للجلسة، وهي المدة التي تُقاس من آخر مرة تم فيها تهيئة ملف تعريف الارتباط. تُعبَّر عن هذه المدة بالثواني. وقد حددنا هنا مدة صلاحية تبلغ 5 دقائق؛

8.3. مبدأ استمرارية المخزن

ملفات تعريف الارتباط المتبادلة بين العميل والخادم متاحة على كلا الجانبين (العميل والخادم) في:

  • [context.app.$cookies] حيث يتوفر الكائن [context]، أي في كل مكان تقريبًا؛
  • [this.$cookies] داخل عرض؛

يمكن الحصول على ملف تعريف ارتباط معين باستخدام التعبير [...$cookies.get(‘nom_du_cookie’)]. يتم تعيين قيمة ملف تعريف الارتباط باستخدام التعبير [...$cookies.set(‘nom_du_cookie’, valeur_du_cookie)].

سيكون مبدأ ملف تعريف الارتباط الدائم للمتجر كما يلي:

  • عندما يقوم الخادم بتهيئة المخزن في الدالة [nuxtServerInit]، سيتم تخزين حالة المخزن في ملف تعريف ارتباط يسمى "session
  • ستصبح ملف تعريف الارتباط "session" عندئذٍ جزءًا من استجابة الخادم HTTP. من المعروف أن المتصفح يعيد إلى الخادم ملفات تعريف الارتباط التي أرسلها إليه. ويقوم بذلك مع كل طلب جديد يوجهه إلى الخادم. ومن المعروف أيضًا أن الخادم يرسل المخزن داخل الصفحة التي يرسلها إلى العميل؛
  • داخل المتصفح، تسترد تطبيق العميل المخزن الذي أرسله الخادم ثم تقوم بعملها. سنحرص على أنه في كل مرة تقوم فيها بتعديل المخزن، يتم تخزين حالته الجديدة في ملف تعريف الارتباط "session" المسجل بواسطة المتصفح؛
  • إذا أجبر المستخدم الخادم على الاستجابة، فسيقوم متصفح العميل تلقائيًا بإعادة إرسال جميع ملفات تعريف الارتباط التي أرسلها الخادم إليه سابقًا، بما في ذلك ملف تعريف الارتباط المسمى "session
  • عندما يقوم الخادم بإعادة تهيئة المخزن مرة أخرى بعد هذا الاستدعاء، سيسترد ملف تعريف الارتباط المسمى "session" ويقوم بتهيئة حالة المخزن بقيمته؛
  • وبالتالي ستكون هناك استمرارية للمتجر بين العميل والخادم؛

8.4. تهيئة المخزن

يتم تنفيذ المخزن في الملف [store / index.js]:


/* eslint-disable no-console */
export const state = () => ({
  // العداد
  counter: 0
})

export const mutations = {
  // زيادة عداد بقيمة واحدة [inc]
  increment(state, inc) {
    state.counter += inc
  },
  // استبدال الحالة
  replace(state, newState) {
    for (const attr in newState) {
      state[attr] = newState[attr]
    }
  }
}

export const actions = {
  async nuxtServerInit(store, context) {
    // من الذي ينفذ هذا الكود؟
    console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server, 'env=', context.env)
    // ننتظر انتهاء وعد
    await new Promise(function(resolve, reject) {
      // عادة ما يكون لدينا هنا دالة غير متزامنة
      // نحاكيها بانتظار لمدة ثانية
      setTimeout(() => {
        // بدء الجلسة
        initStore(store, context)
        // نجاح
        resolve()
      }, 1000)
    })
  }
}

function initStore(store, context) {
  // هل يوجد ملف تعريف ارتباط للجلسة في الطلب الحالي
  const cookies = context.app.$cookies
  const session = cookies.get('session')
  if (!session) {
    // لا توجد جلسة عمل حالية
    console.log("nuxtServerInit, initialisation d'une nouvelle session")
    // يتم تهيئة المخزن
    store.commit('increment', 77)
  } else {
    console.log("nuxtServerInit, reprise d'une session existante")
    // يتم تحديث المخزن باستخدام ملف تعريف ارتباط الجلسة
    store.commit('replace', session.store)
  }
  // وضع المخزن في ملف تعريف ارتباط الجلسة
  cookies.set('session', { store: store.state }, { path: context.base, maxAge: context.env.maxAge })
  // سجل
  console.log('initStore terminé, store=', store.state)
}

تعليقات

  • الأسطر 2-5: سيتكون المخزن من عداد؛
  • الأسطر 9-11: يمكن زيادة هذا العداد؛
  • الأسطر 13-17: يمكن تهيئة حالة المخزن من حالة جديدة. توجد هذه الوظيفة لإظهار إمكانية تهيئة المخزن عندما لا يقتصر على العداد وحده كما هو الحال هنا؛
  • الأسطر 21-35: لم تتغير الوظيفة [nuxtServerInit
  • السطر 30: عند انقضاء فترة الانتظار التي تبلغ ثانية واحدة، يتم تهيئة المخزن باستخدام الوظيفة الموجودة في الأسطر 38-56؛
  • السطران 40-41: نبدأ باسترداد ملف تعريف الارتباط المسمى «session»:
    1. عند تشغيل التطبيق لأول مرة وعند إرسال الطلب الأول إلى الخادم، لن يكون هذا الملف موجودًا بعد. سيتم إنشاؤه عندئذٍ (السطر 53) وإرساله إلى متصفح العميل؛
    2. عند نفس تشغيل التطبيق وعند الطلبات رقم 2 و3 و... الموجهة إلى الخادم، سيكون ملف تعريف الارتباط هذا موجودًا لأن متصفح العميل سيعيد إرساله مع كل طلب جديد موجه إلى الخادم؛
    3. عند تشغيل التطبيق للمرة الثانية وعند إرسال الطلب الأول إلى الخادم، قد يكون ملف تعريف الارتباط هذا موجودًا أيضًا. في الواقع، في نهاية الخطوة 1، تم تخزين ملف تعريف الارتباط على المتصفح مع مدة صلاحية معينة. إذا لم يتم تجاوز مدة الصلاحية هذه، فسيتم إرسال ملف تعريف الارتباط المسمى "session" مع الطلب الأول المرسَل إلى الخادم

باختصار، لكل طلب يتم إرساله إلى الخادم: إذا كانت ملف تعريف الارتباط "session" مخزنة بالفعل على متصفح العميل، فسيتلقاها الخادم، وإلا فلن يتلقاها.

  • الأسطر 42-47: إذا لم يتلقى الخادم ملف تعريف الارتباط الخاص بالجلسة، فسيتم تهيئة المخزن بواسطة السطر 46؛
    • ثم في السطر 53، سيتم إنشاء ملف تعريف ارتباط باسم "session" ووضعه في استجابة الخادم HTTP. قيمة ملف تعريف الارتباط هي الكائن [{ store: store.state }]. وبالتالي، فإن حالة المخزن وليس المخزن نفسه هي التي يتم وضعها في ملف تعريف ارتباط الجلسة؛
    • المعلمة الثالثة للدالة [set] هي كائن خيارات:
      • يحدد [path] إلى أي URL يجب إعادة إرسال ملف تعريف الارتباط هذا. [context.base] هو URL الأساسي لتطبيق [nuxt-05]. ويتم تعريفه في ملف [nuxt.config.js]:

  // الموجه
  router: {
    // جذر URL للتطبيق
    base: '/nuxt-05/'
},
      • [maxAge] هي مدة صلاحية ملف تعريف الارتباط بالثواني على المتصفح. بعد انقضاء هذه المدة، لا يعيد المتصفح إرساله إلى الخادم. [context.env.maxAge] يعيد هنا أيضًا قيمة مسجلة في الملف [nuxt.config.js]:
1
2
3
4
// البيئة
  env: {
    maxAge: 60 * 5
}

[env] هي كلمة رئيسية محجوزة في ملف التكوين. يتم هنا تحديد مدة الصلاحية بـ 5 دقائق. تُقاس هذه المدة بالنسبة لآخر مرة تلقى فيها المتصفح ملف تعريف الارتباط الخاص بالجلسة. بعد انقضاء هذه المدة، لن يتم إعادة إرسال ملف تعريف الارتباط إلى الخادم الذي سيتعين عليه عندئذ بدء جلسة جديدة؛

  • الأسطر 48-50: إذا تلقى الخادم ملف تعريف الارتباط الخاص بالجلسة، يتم تهيئة حالة المخزن باستخدام كائن [store] الخاص بملف تعريف الارتباط الخاص بالجلسة. تذكر أن هذا الكائن يحتوي على حالة المخزن المحفوظة؛
    • ثم في السطر 53، سيتم وضع ملف تعريف الارتباط الخاص بالجلسة في الرد المرسَل إلى متصفح العميل:
      • تقوم الدالة [get] بالبحث عن ملف تعريف الارتباط للجلسة في الطلب الذي استلمه الخادم؛
      • تضع الدالة [set] ملف تعريف ارتباط الجلسة في الرد الذي يرسله الخادم إلى متصفح العميل؛

8.5. زيادة عداد المتجر

تتطور زيادة العداد في الصفحة [index.vue] على النحو التالي:


  // إدارة الأحداث
  methods: {
    incrementCounter() {
      console.log('incrementCounter')
       // زيادة العداد بمقدار 1
      this.$store.commit('increment', 1)
       // تغيير القيمة المعروضة
      this.value = this.$store.state.counter
       // حفظ المخزن في ملف تعريف ارتباط الجلسة
      this.$cookies.set('session', { store: this.$store.state }, { path: this.$nuxt.context.base, maxAge: this.$nuxt.context.env.maxAge })
    }
}

من جانب العميل، في كل مرة يتم فيها تعديل المخزن، يجب حفظه في ملف تعريف ارتباط الجلسة. في الواقع، يمكن للمستخدم طلب URL يدويًا في أي وقت، ويجب أن نكون قادرين عندئذٍ على إرسال مخزن محدث إلى الخادم. لهذا السبب، في السطر 10، بعد زيادة عداد المخزن، يتم حفظ حالته في ملف تعريف ارتباط الجلسة:

  • ملفات تعريف الارتباط متاحة في الخاصية [this.$cookies
  • يتم حفظ حالة المخزن [this.$store.state] في ملف تعريف الارتباط المرتبط بالمفتاح [store
  • مسار ملف تعريف الارتباط هو [context.base]. في إحدى طرق العرض، يتوفر السياق في [this.$nuxt.context
  • مدة صلاحية ملف تعريف الارتباط هي [context.env.maxAge] المتوفرة هنا في الخاصية [this.$nuxt.context.env.maxAge

8.6. تنفيذ المثال [nuxt-05]

نقوم بتشغيل التطبيق [nuxt-05]:

Image

اللقطات التالية مأخوذة من متصفح Chrome. نطلب URL [http://localhost:81/nuxt-05/]. لا تنسَ وضع / في نهاية /nuxt-05، وإلا فلن تحصل على النتائج المرجوة:

Image

  • في [4]، حصلنا على القيمة الأولية للمتجر (77)؛

دعونا نفحص سجلات المتصفح (F12):

Image

  • في [5-6]، سجلات الخادم؛
  • في [7]، نرى أن الخادم يبدأ جلسة جديدة. هذا يعني أنه لم يتلق ملف تعريف ارتباط للجلسة؛
  • في [8]، تهيئة العداد بالقيمة 77؛
  • في [9]، تعرض صفحة [index] الخاصة بالخادم (9) وتلك الخاصة بالعميل (10) نفس قيمة العداد؛

الآن لنلقِ نظرة على ملفات تعريف الارتباط التي استلمها المتصفح:

Image

  • في [1]، اختر علامة التبويب [Application] ثم الخيار [Cookies] [2]. من بين جميع ملفات تعريف الارتباط في متصفحك، اختر ملف تعريف الارتباط الخاص بالمجال [http://localhost:81
  • في [4]، ملف تعريف الارتباط المسمى "session". إذا لم يكن لديك، أعد تحميل الصفحة [F5]: ربما تكون قد تجاوزت مدة صلاحيته التي تبلغ 5 دقائق؛
  • في [5]، قيمة ملف تعريف الارتباط. على الرغم من أن القراءة صعبة بعض الشيء بسبب ترميز الأحرف { :، إلا أنه يمكن تمييز القيمة 77 للعداد؛
  • في [6]، URL لملف تعريف الارتباط: في كل مرة يتم فيها طلب هذا URL، سيرسل المتصفح ملف تعريف الارتباط إلى الخادم؛
  • في [7]، وقت انتهاء صلاحية ملف تعريف الارتباط. عندما يتجاوز هذا الوقت، سيتم حذف ملف تعريف الارتباط من المتصفح؛

تأكد من وجود ملف تعريف الارتباط هذا. إذا لم يكن موجودًا، أعد تحميل الصفحة (F5). عندما تظهر الصفحة مع ملف تعريف الارتباط الخاص بها، أعد تحميل الصفحة مرة أخرى (F5). عندئذٍ تصبح السجلات كما يلي:

Image

هذه المرة في [3]، استرد الخادم ملف تعريف الارتباط الخاص بالجلسة بشكل صحيح. وقد أرسله إليه متصفح العميل.

الآن، قم بزيادة العداد، ثم أعد تحميل الصفحة الحالية من حين لآخر (F5)، سواء كان ذلك [index] أو [page1]، يجب أن تلاحظ أن العداد لا يعود إلى 77 كما في المثال [nuxt-04] بل يحتفظ بالقيمة التي كان عليها في متصفح العميل قبل إعادة تحميل الصفحة:

Image

Image

تكون سجلات المتصفح عندئذٍ كما يلي:

Image

ملاحظة: لأغراض الاختبار، قد تحتاج إلى حذف ملف تعريف الارتباط [5] المخزن على المتصفح لبدء جلسة جديدة، يتم تهيئتها بواسطة الخادم، عند الطلب التالي الموجه إليه.

وأخيرًا، دعونا نوضح تأثير الدالة [incrementCounter] الموجودة في الصفحة [index] على ملف تعريف الارتباط الخاص بالجلسة المخزن في متصفح العميل:


// إدارة الأحداث
  methods: {
    incrementCounter() {
      console.log('incrementCounter')
      // زيادة العداد بمقدار 1
      this.$store.commit('increment', 1)
      // تغيير القيمة المعروضة
      this.value = this.$store.state.counter
      // حفظ المتجر في ملف تعريف ارتباط الجلسة
      this.$cookies.set('session', { store: this.$store.state }, { path: this.$nuxt.context.base, maxAge: this.$nuxt.context.env.maxAge })
    }
  }
  • السطر 10: يتم ترحيل تعديل العداد إلى ملف تعريف ارتباط الجلسة؛

لنتحقق من هذه النقطة. نبدأ من الحالة التالية:

Image

  • في [4]، يعكس عداد ملف تعريف ارتباط الجلسة القيمة المعروضة [1] بشكل صحيح؛

الآن، لنزيد العداد مرة واحدة إلى [5]. تتغير ملف تعريف الارتباط للجلسة في [4] على النحو التالي:

Image

  • إلى [7]، وقد ارتفع عداد ملف تعريف ارتباط الجلسة بالفعل إلى 84. لرؤية ذلك، يجب تحديث العرض [8]. للقيام بذلك، حدد خيارًا آخر من [Storage] [9]، ثم أعد تحديد الخيار [8]. ومن المفترض أن تظهر القيمة الجديدة لملف تعريف الارتباط الخاص بالجلسة؛