مقدمة إلىFetch()

تتيح لك واجهة برمجة التطبيقات fetch() إرسال طلبات شبكة مشابهة لطلبات XMLHttpRequest (XHR). يتمثل الاختلاف الرئيسي في أن واجهة برمجة التطبيقات Fetch API تستخدم الوعود، والتي تحتوي على واجهة برمجة تطبيقات أبسط لمساعدتك على تجنب عمليات الاستدعاء المعقدة في واجهة برمجة التطبيقات XMLHttpRequest API.

Browser Support

  • Chrome: 42.
  • Edge: 14.
  • Firefox: 39.
  • Safari: 10.1.

Source

إذا لم يسبق لك استخدام Promises، يمكنك الاطّلاع على مقدمة حول JavaScript Promises.

طلب Fetch أساسي

إليك مثال على تنفيذ ذلك باستخدام XMLHttpRequest ثم باستخدام fetch. نريد طلب عنوان URL والحصول على استجابة وتحليله كـ JSON.

XMLHttpRequest

يحتاج XMLHttpRequest إلى أداتَي معالجة للتعامل مع حالات النجاح والخطأ، واستدعاء open() وsend(). مثال من مستندات MDN

function reqListener () {
  const data = JSON.parse(this.responseText);
  console.log(data);
}

function reqError (err) {
  console.log('Fetch Error :-S', err);
}

const oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

جلب

يبدو طلب الجلب على النحو التالي:

fetch('./api/some.json')
  .then(response => {
    if (response.status !== 200) {
      console.log(`Looks like there was a problem. Status Code: ${response.status}`);

      return;
    }

    // Examine the text in the response
    response.json().then(function(data) {
      console.log(data);
    });
  })
  .catch(err => {
    console.log('Fetch Error :-S', err);
  });

يتطلب طلب fetch() مكالمة واحدة فقط لتنفيذ نفس العمل مثل مثال XHR. لمعالجة الاستجابة، نتحقق أولاً من أن حالة الاستجابة هي 200، ثم نحلل الاستجابة كـ JSON. الردّ على طلب fetch() هو عنصر Stream، ما يعني أنّه بعد استدعاء طريقة json()، يتم عرض Promise. يتم البث بشكل غير متزامن.

البيانات الوصفية للردّ

أظهر المثال السابق حالة عنصر Response، وكيفية تحليل الاستجابة كملف JSON. في ما يلي كيفية التعامل مع البيانات الوصفية الأخرى التي قد تحتاج إلى الوصول إليها، مثل العناوين:

fetch('users.json').then(response => {
  console.log(response.headers.get('Content-Type'));
  console.log(response.headers.get('Date'));

  console.log(response.status);
  console.log(response.statusText);
  console.log(response.type);
  console.log(response.url);
});

أنواع الردود

عندما نرسل طلب جلب، سيتم منح الاستجابة response.type "basic" أو "cors" أو "opaque". توضّح هذه types مصدر المورد، ويمكنك استخدامها لتحديد كيفية التعامل مع عنصر الاستجابة.

عندما يطلب المتصفّح موردًا من المصدر نفسه، يتضمّن الردّ نوع basic مع فرض قيود على ما يمكنك الاطّلاع عليه من الردّ.

إذا تم تقديم طلب لمورد من مصدر آخر، وأرجع هذا المصدر عناوين CORS، يكون النوع cors. تتشابه استجابات cors مع استجابات basic، ولكنها تقيّد الرؤوس التي يمكنك عرضها على Cache-Control وContent-Language وContent-Type وExpires وLast-Modified وPragma.

تأتي ردود opaque من مصدر مختلف لا يعرض عناوين CORS. باستخدام الاستجابة المبهمة، لن نتمكّن من قراءة البيانات التي تم عرضها أو الاطّلاع على حالة الطلب، ما يعني أنّه لا يمكنك التحقّق مما إذا كان الطلب ناجحًا أم لا.

يمكنك تحديد وضع لطلب جلب معيّن بحيث يتم حلّ أنواع معيّنة فقط من الطلبات. في ما يلي الأوضاع التي يمكنك ضبطها:

  • لا تنجح دالة same-origin إلا في طلبات مواد العرض من المصدر نفسه، وترفض جميع الطلبات الأخرى.
  • يسمح cors بطلبات الحصول على مواد العرض من المصدر نفسه والمصادر الأخرى التي تعرض عناوين CORS المناسبة.
  • يُجري cors-with-forced-preflight فحصًا أوليًا قبل إرسال أي طلب.
  • تم تصميم no-cors لإرسال الطلبات إلى مصادر أخرى لا تحتوي على عناوين CORS وتؤدي إلى استجابة opaque، ولكن كما ذكرنا، لا يمكن تنفيذ ذلك في النطاق العام للنافذة في الوقت الحالي.

لتحديد الوضع، أضِف عنصر خيارات كمَعلمة ثانية في طلب fetch وحدِّد الوضع في ذلك العنصر:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
  .then(response => response.text())
  .then(text => {
    console.log('Request successful', text);
  })
  .catch(error => {
    log('Request failed', error)
  });

سلسلة الوعود

من الميزات الرائعة لـ "الوعود" هي إمكانية ربطها معًا. بالنسبة إلى fetch()، يتيح لك ذلك مشاركة المنطق في طلبات الجلب.

إذا كنت تعمل مع واجهة برمجة تطبيقات JSON، عليك التحقّق من الحالة وتحليل JSON لكل استجابة. يمكنك تبسيط الرمز من خلال تحديد الحالة وتحليل JSON في دوال منفصلة تعرض الوعود، واستخدام طلب الجلب للتعامل مع البيانات النهائية وحالة الخطأ فقط.

function status (response) {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(new Error(response.statusText))
  }
}

function json (response) {
  return response.json()
}

fetch('users.json')
  .then(status)
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  }).catch(error => {
    console.log('Request failed', error);
  });

يحدّد هذا المثال دالة status تتحقّق من response.status وتعرض إما Promise تم حلّه على شكل Promise.resolve() أو Promise تم رفضه على شكل Promise.reject(). هذه هي الطريقة الأولى التي يتم طلبها في سلسلة fetch().

إذا تم حلّ الوعد، يستدعي النص البرمجي طريقة json() التي تعرض وعدًا ثانيًا من استدعاء response.json() وتنشئ كائنًا يحتوي على JSON الذي تم تحليله. إذا فشل التحليل، يتم رفض الوعد ويتم تنفيذ عبارة catch.

تتيح لك هذه البنية مشاركة المنطق في جميع طلبات الجلب، ما يسهّل صيانة الرمز البرمجي وقراءته واختباره.

طلب POST

في بعض الأحيان، يحتاج تطبيق الويب إلى استدعاء واجهة برمجة تطبيقات باستخدام طريقة POST وتضمين بعض المَعلمات في نص الطلب. لإجراء ذلك، اضبط مَعلمتَي method وbody في خيارات fetch():

fetch(url, {
    method: 'post',
    headers: {
      "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
  })
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(error => {
    console.log('Request failed', error);
  });

إرسال بيانات الاعتماد مع طلب جلب

لإجراء طلب جلب باستخدام بيانات اعتماد مثل ملفات تعريف الارتباط، اضبط قيمة credentials للطلب على "include":

fetch(url, {
  credentials: 'include'
})