מבוא ל-fetch()

‫fetch() מאפשר לשלוח בקשות לאחזור מהרשת בדומה ל-XMLHttpRequest ‏ (XHR). ההבדל העיקרי הוא שב-Fetch API משתמשים ב-Promises, שכולל 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);
  });

כדי לבצע את אותה פעולה כמו בדוגמה של XHR, צריך רק קריאה אחת בבקשת fetch(). כדי לעבד את התגובה, קודם אנחנו בודקים שסטטוס התגובה הוא 200, ואז מנתחים את התגובה כ-JSON. התגובה לבקשה fetch() היא אובייקט Stream, כלומר אחרי ששולחים קריאה ל-method‏ 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)
  });

שרשור הבטחות (Promise chaining)

אחת התכונות הנהדרות של הבטחות היא היכולת לשרשר אותן יחד. ב-fetch(), זה מאפשר לכם לשתף לוגיקה בין בקשות אחזור.

אם אתם עובדים עם API בפורמט JSON, אתם צריכים לבדוק את הסטטוס ולנתח את ה-JSON של כל תגובה. כדי לפשט את הקוד, אפשר להגדיר את הסטטוס ואת ניתוח ה-JSON בפונקציות נפרדות שמחזירות הבטחות, ולהשתמש בבקשת ה-fetch כדי לטפל רק בנתונים הסופיים ובמקרה של שגיאה.

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(). זו ה-method הראשונה שמופעלת בשרשרת fetch().

אם ה-Promise נפתר, הסקריפט קורא ל-method‏ json(), שמחזירה Promise שני מהקריאה ל-response.json() ויוצרת אובייקט שמכיל את ה-JSON המנותח. אם הניתוח נכשל, ה-Promise נדחה והצהרת ה-catch מופעלת.

המבנה הזה מאפשר לכם לשתף את הלוגיקה בכל בקשות השליפה, וכך קל יותר לתחזק, לקרוא ולבדוק את הקוד.

בקשת POST

לפעמים אפליקציית אינטרנט צריכה לשלוח קריאה ל-API באמצעות שיטת 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);
  });

שליחת פרטי כניסה עם בקשת אחזור

כדי לשלוח בקשת אחזור עם פרטי כניסה כמו קובצי Cookie, מגדירים את הערך credentials של הבקשה ל-"include":

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