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',
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    // https://www.npmjs.com/package/cookie-universal-nuxt
    'cookie-universal-nuxt'
  ],
...

  • در خط ۱۲، ماژول [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: [
    // Doc: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Doc: 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: {
    // ریشهٔ برنامه
    base: '/nuxt-05/'
  },
  // سرور
  server: {
    // پورت سرویس، به‌طور پیش‌فرض 3000
    port: 81,
    // آدرس‌های شبکه‌ای که گوش داده می‌شوند، پیش‌فرض localhost: 127.0.0.1
    // 0.0.0.0 = تمام آدرس‌های شبکه روی دستگاه
    host: 'localhost'
  },
  // محیط
  env: {
    maxAge: 60 * 5
  }
}
  • خط ۷۹: کلید [env] به فایل اضافه شده است. این کلید یک کلمهٔ محفوظ است. عناصر اعلام‌شده در این شیء از طریق شیء [context.env] در عناصر برنامه در دسترس هستند؛
  • خط ۸۰: ویژگی [maxAge] حداکثر عمر کوکی جلسه خواهد بود که از آخرین باری که کوکی اولیه شده است، اندازه‌گیری می‌شود. این مدت به ثانیه بیان می‌شود. در اینجا، عمر ۵ دقیقه تنظیم شده است؛

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 را تشکیل خواهد داد. ما می‌دانیم که یک مرورگر، کوکی‌هایی را که سرور برایش ارسال کرده است، به سرور بازمی‌گرداند. این کار را در هر درخواست جدیدی که به سرور ارسال می‌کند، انجام می‌دهد. همچنین می‌دانیم که سرور، store را در داخل صفحه‌ای که برای کلاینت ارسال می‌کند، می‌فرستد؛
  • در داخل مرورگر، برنامهٔ کلاینت، فروشگاه ارسال‌شده توسط سرور را بازیابی می‌کند و سپس وظایف خود را انجام می‌دهد. ما اطمینان حاصل خواهیم کرد که هر بار که فروشگاه را تغییر می‌دهد، وضعیت جدید آن در کوکی «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)
}

نظرات

  • خطوط ۲–۵: مخزن از یک شمارنده تشکیل خواهد شد؛
  • خطوط ۹–۱۱: این شمارنده می‌تواند افزایش یابد؛
  • خطوط ۱۳–۱۷: وضعیت ذخیره‌گاه را می‌توان از یک وضعیت جدید اولیه کرد. این تابع برای نشان دادن یک روش ممکن برای اولیه کردن ذخیره‌گاه زمانی که به یک شمارنده محدود نیست، گنجانده شده است، همان‌طور که در اینجا نیز هست؛
  • خطوط ۲۱–۳۵: تابع [nuxtServerInit] تغییر نکرده است؛
  • خط ۳۰: پس از اتمام تایم‌اوت یک ثانیه‌ای، حافظه با استفاده از تابع موجود در خطوط ۳۸–۵۶ مقداردهی اولیه می‌شود؛
  • خطوط ۴۰–۴۱: ما با بازیابی کوکی با نام «session» شروع می‌کنیم:
    1. وقتی برنامه برای اولین بار اجرا می‌شود و اولین درخواست به سرور ارسال می‌گردد، این کوکی هنوز وجود ندارد. سپس ایجاد شده (خط ۵۳) و به مرورگر کلاینت ارسال می‌شود؛
    2. در طول همان اجرای برنامه و برای درخواست‌های ۲، ۳ و ... که به سرور ارسال می‌شوند، این کوکی وجود خواهد داشت زیرا مرورگر کلاینت آن را با هر درخواست جدید به سرور بازمی‌فرستد؛
    3. در دومین اجرای برنامه و در اولین درخواست ارسال‌شده به سرور، این کوکی ممکن است وجود داشته باشد. این به آن دلیل است که در پایان مرحله ۱، کوکی با یک عمر مفید مشخص در مرورگر ذخیره شده بود. اگر این عمر مفید هنوز منقضی نشده باشد، کوکی با نام «session» با اولین درخواست ارسال‌شده به سرور ارسال خواهد شد.

خلاصه اینکه، برای هر درخواست ارسال‌شده به سرور: اگر کوکی «session» از قبل در مرورگر کلاینت ذخیره شده باشد، سرور آن را دریافت خواهد کرد؛ در غیر این صورت، آن را دریافت نخواهد کرد.

  • خطوط ۴۲–۴۷: اگر سرور کوکی جلسه را دریافت نکند، در این صورت با خط ۴۶ فروشگاه راه‌اندازی می‌شود؛
    • سپس، در خط ۵۳، یک کوکی به نام «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] یک کلمه کلیدی رزرو شده در فایل پیکربندی است. در اینجا، عمر آن روی ۵ دقیقه تنظیم شده است. این مدت زمان از آخرین باری که مرورگر کوکی جلسه را دریافت کرده است، اندازه‌گیری می‌شود. پس از اتمام این مدت، کوکی دیگر به سرور ارسال نخواهد شد و سرور باید یک جلسه جدید را آغاز کند؛

  • خطوط ۴۸–۵۰: اگر سرور کوکی جلسه را دریافت کند، آنگاه وضعیت فروشگاه با استفاده از شی [store] موجود در کوکی جلسه، مقداردهی اولیه می‌شود. به یاد داشته باشید که این شی شامل وضعیت ذخیره‌شده فروشگاه است؛
    • سپس، در خط ۵۳، کوکی جلسه در پاسخ ارسال‌شده به مرورگر کلاینت گنجانده می‌شود:
      • تابع [get] کوکی جلسه را از درخواست دریافت‌شده توسط سرور بازیابی می‌کند؛
      • تابع [set] کوکی جلسه را در پاسخ سرور به مرورگر مشتری قرار می‌دهد؛

8.5. افزایش شمارنده فروشگاه

شمارنده در صفحه [index.vue] به شرح زیر افزایش می‌یابد:


  // مدیریت رویداد
  methods: {
    incrementCounter() {
      console.log('incrementCounter')
       // شمارنده را ۱ واحد افزایش دهید
      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 را درخواست کند، و بنابراین ما باید بتوانیم یک فروشگاه به‌روز را به سرور ارسال کنیم. به همین دلیل، در خط ۱۰، پس از افزایش شمارنده مخزن، وضعیت آن را در کوکی جلسه ذخیره می‌کنیم:

  • کوکی‌ها در ویژگی [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

تصاویر زیر از مرورگر کروم هستند. ما URL [http://localhost:81/nuxt-05/] را درخواست می‌کنیم. فراموش نکنید که / نهایی را بعد از /nuxt-05 اضافه کنید، در غیر این صورت نتایج مورد انتظار را نخواهید گرفت:

Image

  • در [4]، مقدار اولیه store (77) را به دست آوردیم؛

بیایید لاگ‌های مرورگر را بررسی کنیم (F12):

Image

  • در [5-6]، لاگ‌های سرور را مشاهده می‌کنیم؛
  • در [7]، می‌توانیم ببینیم که سرور یک جلسه جدید را آغاز می‌کند. این بدان معناست که کوکی جلسه را دریافت نکرده است؛
  • در [8]، شمارنده با مقدار 77 مقداردهی اولیه می‌شود؛
  • در [9]، صفحه [index] هم روی سرور (9) و هم روی کلاینت (10) یکسان بودن مقدار شمارنده را نمایش می‌دهد؛

اکنون بیایید به کوکی‌های دریافت‌شده توسط مرورگر نگاهی بیندازیم:

Image

  • در [1]، زبانه [Application] را انتخاب کنید، سپس گزینه‌های [Cookies] و [2] را. از میان تمام کوکی‌های مرورگر خود، کوکی متعلق به دامنه [http://localhost:81] را انتخاب کنید؛
  • در [4]، کوکی با نام «session». اگر آن را ندارید، صفحه [F5] را دوباره بارگذاری کنید: شاید دورهٔ عمر ۵ دقیقه‌ای آن منقضی شده باشد؛
  • در [5]، مقدار کوکی. اگرچه به دلیل رمزگذاری کاراکترها { :، مقدار ۷۷ شمارنده قابل تشخیص است؛
  • در [6]، بخش URL کوکی: هر بار که این URL درخواست شود، مرورگر کوکی را به سرور ارسال می‌کند؛
  • در [7]، زمان انقضای کوکی. پس از گذشت این زمان، کوکی از مرورگر حذف خواهد شد؛

مطمئن شوید که این کوکی را دارید. اگر آن را ندارید، صفحه را دوباره بارگیری کنید (F5). پس از اینکه صفحه با کوکی آن را دریافت کردید، دوباره صفحه را بارگیری کنید (F5). سپس لاگ‌ها به شرح زیر خواهند بود:

Image

این بار، در [3]، سرور با موفقیت کوکی جلسه را بازیابی کرده است. این کوکی توسط مرورگر کلاینت برای آن ارسال شده بود.

اکنون، شمارنده را افزایش دهید، سپس گهگاه صفحه فعلی را دوباره بارگذاری کنید (F5)، چه [index] باشد یا [page1]، شما باید متوجه شوید که شمارنده مانند مثال [nuxt-04] به ۷۷ بازنمی‌گردد، بلکه مقداری را که قبل از بارگذاری مجدد صفحه در مرورگر کلاینت داشت، حفظ می‌کند:

Image

Image

لاگ‌های مرورگر سپس به شرح زیر است:

Image

توجه: برای اهداف آزمایشی، ممکن است لازم باشد کوکی جلسه [5] را که در مرورگر ذخیره شده است، حذف کنید تا در درخواست بعدی به سرور، یک جلسه جدید که توسط سرور راه‌اندازی شده است، آغاز شود.

در نهایت، بیایید به تأثیر تابع [incrementCounter] بر صفحه [index] بر کوکی جلسه ذخیره شده در مرورگر مشتری نگاهی بیندازیم:


// پردازش رویداد
  methods: {
    incrementCounter() {
      console.log('incrementCounter')
      // افزایش شمارنده به اندازه ۱
      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 })
    }
  }
  • خط ۱۰: تغییر در شمارنده در کوکی جلسه منعکس می‌شود؛

بیایید این را بررسی کنیم. با سناریوی زیر شروع می‌کنیم:

Image

  • در [4]، شمارنده کوکی جلسه به درستی مقدار نمایش داده شده در [1] را منعکس می‌کند؛

اکنون یک بار شمارنده را افزایش می‌دهیم تا به [5] برسد. کوکی جلسه که [4] بود، به شرح زیر تغییر می‌کند:

Image

  • به [7]؛ شمارنده کوکی جلسه واقعاً به ۸۴ افزایش یافته است. برای مشاهده این، نما [8] را تازه کنید. برای انجام این کار، یک گزینه دیگر را از [Storage] یا [9] انتخاب کنید، سپس دوباره گزینه [8] را انتخاب کنید. در این صورت، مقدار جدید کوکی جلسه باید ظاهر شود؛