Skip to content

12. پروژه [vuejs-10]: پلاگین [dao]، درخواست‌های ناهمزمان HTTP

ساختار پروژه برای [vuejs-10] به شرح زیر است:

Image

پروژه [vuejs-10] نشان می‌دهد که یک کامپوننت درخواستی HTTP را به یک سرور راه دور ارسال می‌کند. معماری مورد استفاده به شرح زیر است:

Image

یک کامپوننت [Vue.js] از لایه [dao] برای ارتباط با سرور محاسبه مالیات استفاده می‌کند.

12.1. نصب وابستگی‌ها

برنامه [vuejs-10] از کتابخانه [axios] برای ارسال درخواست‌های غیرهمزمان به سرور محاسبه مالیات استفاده می‌کند. ما باید این وابستگی را نصب کنیم:

Image

  • در [4-5]، خطی که پس از نصب کتابخانه [axios] به فایل [package.json] اضافه می‌شود، [1-3] است؛

12.2. کلاس [Dao]

کلاس [Dao] همان کلاسی است که در بخش [La classe Dao] توسعه یافته است. ما آن را برای مرجع در اینجا بازنشر می‌کنیم:


'use strict';

// واردات‌ها
import qs from 'qs'

// class [Dao]
class Dao {

  // سازنده
  constructor(axios) {
    this.axios = axios;
    // کوکی جلسه
    this.sessionCookieName = "PHPSESSID";
    this.sessionCookie = '';
  }

  // راه‌اندازی جلسه
  async  initSession() {
    // گزینه‌های درخواست HHTP [get /main.php?action=init-session&type=json]
    const options = {
      method: "GET",
      //URL پارامترها
      params: {
        action: 'init-session',
        type: 'json'
      }
    };
    //اجرای پرس‌وجو HTTP
    return await this.getRemoteData(options);
  }

  async  authentifierUtilisateur(user, password) {
    // گزینه‌های درخواست HHTP [post /main.php?action=authentifier-utilisateur]
    const options = {
      method: "POST",
      headers: {
        'Content-type': 'application/x-www-form-urlencoded',
      },
      // بدنهٔ POST
      data: qs.stringify({
        user: user,
        password: password
      }),
      //پارامترهای URL
      params: {
        action: 'authentifier-utilisateur'
      }
    };
    // اجرای پرس‌وجو HTTP
    return await this.getRemoteData(options);
  }

  async getAdminData() {
    // گزینه‌ها برای پرس‌وجوی HHTP  [get /main.php?action=get-admindata]
    const options = {
      method: "GET",
      //پارامترها برای URL
      params: {
        action: 'get-admindata'
      }
    };
    // اجرای پرس‌وجو HTTP
    const data = await this.getRemoteData(options);
    // نتیجه
    return data;
  }

  async  getRemoteData(options) {
    //برای کوکی جلسه
    if (!options.headers) {
      options.headers = {};
    }
    options.headers.Cookie = this.sessionCookie;
    //اجرای درخواست HTTP
    let response;
    try {
      // درخواست ناهمزمان
      response = await this.axios.request('main.php', options);
    } catch (error) {
      // پارامتر [error] یک نمونه استثنا است – می‌تواند اشکال مختلفی داشته باشد
      if (error.response) {
        // پاسخ سرور در [error.response] است
        response = error.response;
      } else {
        //خطا مجدداً فعال می‌شود
        throw error;
      }
    }
    //«response» کل پاسخ HTTP از سرور است (سربرگ‌های HTTP + خود پاسخ)
    // کوکی جلسه را در صورت وجود بازیابی می‌کند
    const setCookie = response.headers['set-cookie'];
    if (setCookie) {
      // setCookie یک آرایه است
      // کوکی جلسه در این آرایه جستجو می‌شود
      let trouvé = false;
      let i = 0;
      while (!trouvé && i < setCookie.length) {
        //جستجوی کوکی جلسه
        const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
        if (results) {
          // کوکی جلسه ذخیره می‌شود
          //eslint-disable-next-line require-atomic-updates
          this.sessionCookie = results[1];
          // پیدا شد
          trouvé = true;
        } else {
          // عنصر بعدی
          i++;
        }
      }
    }
    // پاسخ سرور در [response.data] است
    return response.data;
  }
}

// صادرات کلاس
export default Dao;

پروژه [vuejs-10] تنها از روش غیرهمزمان [initSession] در خطوط ۱۸–۳۰ استفاده می‌کند. شایان ذکر است که کلاس [Dao] با پارامتر [axios] (خط ۱۰) instance می‌شود که توسط کد فراخوانی مقداردهی اولیه می‌گردد. در این مورد، کد فراخوانی اسکریپت [./main.js] است.

12.3. پلاگین [pluginDao]

پلاگین [pluginDao] به شرح زیر است:


export default {
  install(Vue, dao) {
    //یک ویژگی [$dao] را به کلاس Vue اضافه می‌کند
    Object.defineProperty(Vue.prototype, '$dao', {
      //وقتی به Vue.$dao ارجاع داده می‌شود، پارامتر دوم [dao] بازگردانده می‌شود
      get: () => dao,
    })
  }
}

اگر توضیح ارائه‌شده برای پلاگین [event-bus] را به یاد بیاوریم، می‌توانیم ببینیم که پلاگین [pluginDao]، درون کلاس/فنکشن [Vue]، یک ویژگی جدید به نام [$dao] ایجاد می‌کند. این ویژگی (همان‌طور که بعداً نشان داده خواهد شد) مقدار آن شیء صادرشده توسط اسکریپت [./Dao]، یعنی کلاس قبلی [Dao]، خواهد بود.

12.4. اسکریپت اصلی [main.js]

کد اسکریپت اصلی [main.js] به شرح زیر است:


//وارد می‌کند
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios';

// افزونه‌ها
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);

//بوت‌استرپ
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

//لایه [dao]
import Dao from './Dao';
// پیکربندی axios
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/taxes/version-14';
axios.defaults.withCredentials = true;
// نمونه سازی لایه [dao]
const dao = new Dao(axios);

// [dao] افزونه
import pluginDao from './plugins/dao'
Vue.use(pluginDao, dao)

// پیکربندی
Vue.config.productionTip = false

// پروژهٔ نمونه‌سازی [App]
new Vue({
  render: h => h(App),
}).$mount('#app')

اسکریپت [main.js]:

  • لایه [dao] را در خطوط 14–21 ایجاد می‌کند؛
  • پلاگین [pluginDao] را در خطوط 24–25 یکپارچه می‌کند؛
  • خط ۱۵: کلاس [Dao] وارد می‌شود؛
  • خطوط ۱۷–۱۸: شیء [axios] که پرس‌وجوهای HTTP را اجرا می‌کند، پیکربندی شده است. این شیء در خط ۴ وارد شده است؛
    • خط ۱۷: تعریف یک [timeout] با مدت زمان ۲ ثانیه؛
    • خط ۱۸: URL برای سرور محاسبه مالیات؛
    • خط ۱۹: برای فعال کردن تبادل کوکی‌ها با سرور؛
  • خطوط ۲۴–۲۵: استفاده از افزونه [pluginDao]
    • خط ۲۴: وارد کردن پلاگین؛
    • خط ۲۵: یکپارچه‌سازی افزونه. می‌بینیم که پارامتر دوم متد [Vue.useارجاع به لایه [dao] تعریف‌شده در خط ۲۱ است. به همین دلیل، خاصیت [Vue.$dao] در تمام نمونه‌های کلاس/تابع [Vue]، یعنی در تمام کامپوننت‌های [Vue.js]، به لایه [dao] ارجاع خواهد داد؛

12.5. نما اصلی [App.vue]

کد نمای اصلی [App] به شرح زیر است:


<template>
  <div class="container">
    <b-card>
      <!-- پیام -->
      <b-alert show variant="success" align="center">
        <h4>[vuejs-10] : plugin [dao], requêtes HTTP asynchrones</h4>
      </b-alert>
      <!-- کامپوننت در حال ارسال درخواست ناهمزمان به سرور محاسبه مالیات-->
      <Component1 @error="doSomethingWithError" @endWaiting="endWaiting" @beginWaiting="beginWaiting" />
      <!--نمایش هرگونه خطا -->
      <b-alert show
               variant="danger"
               v-if="showError">Evénement [error] intercepté par [App]. Valeur reçue = {{error}}</b-alert>
      <!-- پیام در حال انتظار با چرخ‌وفلک -->
      <b-alert show v-if="showWaiting" variant="light">
        <strong>Requête au serveur de calcul d'impôt en cours...</strong>
        <b-spinner variant="primary" label="Spinning"></b-spinner>
      </b-alert>
    </b-card>
  </div>
</template>

<script>
  import Component1 from "./components/Component1";
  export default {
    name: "app",
    //وضعیت کامپوننت
    data() {
      return {
        // کنترل چرخ‌دنده‌ی بارگذاری
        showWaiting: false,
        //کنترل نمایش خطا
        showError: false,
        //خطای دریافت‌شده
        error: {}
      };
    },
    // کامپوننت‌های استفاده شده
    components: {
      Component1
    },
    // روش‌های رسیدگی به رویدادها
    methods: {
      // شروع انتظار
      beginWaiting() {
        // نمایش زمان انتظار
        this.showWaiting = true;
        // پنهان کردن پیام خطا
        this.showError = false;
      },
      //پایان انتظار
      endWaiting() {
        // پنهان کردن زمان انتظار
        this.showWaiting = false;
      },
      // پردازش خطا
      doSomethingWithError(error) {
        // توجه کنید که خطایی رخ داده است
        this.error = error;
        // نمایش پیام خطا
        this.showError = true;
      }
    }
  };
</script>

نظرات

  • خط ۹: [Component1] کامپوننتی است که درخواست ناهمزمان HTTP را انجام می‌دهد. این کامپوننت می‌تواند سه رویداد را فعال کند:
    • [beginWaiting]: درخواست در شرف ارسال است. باید پیامی با مضمون «لطفاً منتظر بمانید» به کاربر نمایش داده شود؛
    • [endWaiting]: درخواست تکمیل شده است. انتظار باید پایان یابد؛
    • [error]: درخواست با موفقیت‌آمیز بودن. یک پیام خطا باید نمایش داده شود؛
  • خطوط ۱۰–۱۳: هشداری که هر پیام خطایی را نمایش می‌دهد. این هشدار توسط متغیر بولی [showError] در خط ۳۳ کنترل می‌شود. این متغیر خطا را در خط ۳۵ نمایش می‌دهد؛
  • خطوط 14–18: هشداری که پیام بارگذاری را با یک چرخ‌وفلک نمایش می‌دهد. این هشدار توسط متغیر بولی [showWaiting] در خط 47 کنترل می‌شود؛
  • خطوط ۴۵–۵۰: [beginWaiting] متدی است که هنگام دریافت رویداد [beginWaiting] اجرا می‌شود. این متد پیام بارگذاری (خط ۴۷) را نمایش می‌دهد و در صورتی که پیام خطا پس از یک عملیات قبلی هنوز قابل مشاهده باشد، آن را پنهان می‌کند؛
  • خطوط ۵۲–۵۵: [endWaiting] متدی است که هنگام دریافت رویداد [endWaiting] اجرا می‌شود. این پیام در انتظار (خط ۵۴) را مخفی می‌کند؛
  • خطوط ۵۷–۶۲: [doSomethingWithError] متدی است که هنگام دریافت رویداد [error] اجرا می‌شود. این متد خطای دریافت‌شده را ثبت می‌کند (خط ۵۹) و پیام خطا را نمایش می‌دهد (خط ۶۱)؛

12.6. کامپوننت [Component1]

کد کامپوننت [Component1] به شرح زیر است:


<template>
  <b-row>
    <b-col>
      <b-alert show
               variant="warning"
               v-if="showMsg">Valeur reçue du serveur = {{data}}</b-alert>
    </b-col>
  </b-row>
</template>

<script>
  export default {
    name: "component1",
    //وضعیت مؤلفه
    data() {
      return {
        showMsg: false
      };
    },
    // روش‌های رسیدگی به رویدادها
    methods: {
      //پردازش داده‌های دریافتی از سرور
      doSomethingWithData(data) {
        //داده‌های دریافتی ذخیره می‌شوند
        this.data = data;
        //نمایش آن
        this.showMsg = true;
      }
    },
    // کامپوننت به‌تازگی ایجاد شده است
    created() {
      // ابتدایی‌سازی جلسه با سرور – درخواست ناهمزمان
      // از وعده‌ای که توسط متدهای لایه [dao] بازگردانده می‌شود استفاده می‌شود
      // نشان‌دهنده شروع عملیات
      this.$emit("beginWaiting");
      // راه‌اندازی عملیات ناهمزمان
      this.$dao
        // این شامل راه‌اندازی یک جلسه jSON با سرور محاسبه مالیات است
        .initSession()
        // روشی که در صورت موفقیت داده‌های دریافتی را پردازش می‌کند
        .then(data => {
          //داده‌های دریافتی پردازش می‌شوند
          this.doSomethingWithData(data);
        })
        // روشی که در صورت خطا، خطا را مدیریت می‌کند
        .catch(error => {
          //خطا به کامپوننت والد ارجاع داده می‌شود
          this.$emit("error", error.message);
        }).finally(() => {
          //پایان انتظار
          this.$emit("endWaiting");
        })
    }
  };
</script>

نظرات

  • خطوط ۴–۶: این کامپوننت شامل یک هشدار واحد است که مقدار بازگشتی از سرور محاسبه مالیات را نمایش می‌دهد، اما فقط در صورتی که پرس‌وجوی HTTP موفق باشد. این هشدار توسط متغیر بولی [showMsg] در خط 17 کنترل می‌شود؛
  • خطوط ۳۱–۵۳: درخواست HTTP به محض ایجاد کامپوننت انجام می‌شود. بنابراین کد آن در متد [created] در خط ۳۱ قرار داده شده است؛
  • خط ۳۵: به کامپوننت والد اطلاع داده می‌شود که درخواست غیرهمزمان در شرف شروع است؛
  • خطوط ۳۷–۳۹: متد [this.$dao.initSession] اجرا می‌شود. این متد یک جلسه jSON را با سرور محاسبه مالیات راه‌اندازی می‌کند. نتیجه فوری این متد یک [Promise] است؛
  • خطوط ۴۱–۴۴: این کد زمانی اجرا می‌شود که سرور نتیجه خود را بدون هیچ خطایی بازگردانده باشد. نتیجه سرور در [data] ذخیره می‌شود. در خط ۴۳، متد [doSomethingWithData] برای پردازش این نتیجه فراخوانی می‌شود؛
  • خطوط ۴۶–۴۹: این کد در صورتی اجرا می‌شود که هنگام اجرای درخواست خطایی رخ دهد. در خط ۴۸، به کامپوننت والد اطلاع داده می‌شود که خطایی رخ داده است و پیام خطای [error.message] به آن ارسال می‌شود؛
  • خطوط ۴۹–۵۲: این کد در همه موارد اجرا می‌شود. به کامپوننت والد اطلاع داده می‌شود که درخواست HTTP تکمیل شده است؛
  • خطوط 23–28: متد [doSomethingWithData] مسئول پردازش داده‌های [data] ارسال‌شده توسط سرور است. در خط 25 این داده‌ها ذخیره می‌شوند و در خط 27 نمایش داده می‌شوند؛

12.7. اجرای پروژه

Image

اگر هنگام راه‌اندازی پروژه، سرور محاسبه مالیات در حال اجرا نباشد، نتیجه زیر به دست می‌آید:

Image

بیایید سرور [Laragon] را راه‌اندازی کنیم (به https://tahe.developpez.com/tutoriels-cours/php7 مراجعه کنید) و صفحه بالا را دوباره بارگذاری کنیم. نتیجه به شرح زیر است:

Image

توجه: ما از نسخه 14 سرور محاسبه مالیات، همان‌طور که در https://tahe.developpez.com/tutoriels-cours/php7 تعریف شده است، استفاده می‌کنیم.