Giới thiệu về hàm tìm nạp()

fetch() cho phép bạn thực hiện các yêu cầu mạng tương tự như XMLHttpRequest (XHR). Điểm khác biệt chính là API Tìm nạp sử dụng Promises, có một API đơn giản hơn để giúp bạn tránh các lệnh gọi lại phức tạp trong API XMLHttpRequest.

Hỗ trợ trình duyệt

  • 42
  • 14
  • 39
  • 10.1

Nguồn

Nếu trước đây bạn chưa từng sử dụng Promise, hãy xem phần Giới thiệu về JavaScript Promise.

Yêu cầu tìm nạp cơ bản

Dưới đây là ví dụ được triển khai bằng XMLHttpRequest, sau đó bằng fetch. Chúng ta muốn yêu cầu một URL, nhận phản hồi và phân tích cú pháp URL đó dưới dạng JSON.

XMLHttpRequest

XMLHttpRequest cần có hai trình nghe để xử lý các trường hợp thành công và lỗi, cũng như một lệnh gọi đến open()send(). Ví dụ trong các tài liệu về MDN.

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

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

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

Tìm nạp

Yêu cầu tìm nạp của chúng ta như sau:

fetch('./api/some.json')
  .then(
  function(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(function(err) {
    console.log('Fetch Error :-S', err);
  });

Yêu cầu fetch() chỉ cần một lệnh gọi để thực hiện công việc tương tự như ví dụ về XHR. Để xử lý phản hồi, trước tiên, chúng tôi kiểm tra để đảm bảo trạng thái phản hồi là 200, sau đó phân tích cú pháp phản hồi dưới dạng JSON. Phản hồi cho yêu cầu fetch() là đối tượng Stream (Luồng), nghĩa là sau khi chúng ta gọi phương thức json(), một Promise sẽ được trả về. Luồng xảy ra một cách không đồng bộ.

Siêu dữ liệu của phản hồi

Ví dụ trước cho thấy trạng thái của đối tượng Response (Phản hồi) và cách phân tích cú pháp phản hồi dưới dạng JSON. Dưới đây là cách xử lý siêu dữ liệu khác mà bạn có thể muốn truy cập, chẳng hạn như tiêu đề:

fetch('users.json').then(function(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);
});

Loại phản hồi

Khi chúng tôi đưa ra yêu cầu tìm nạp, phản hồi sẽ được cung cấp response.type là "basic", "cors" hoặc "opaque". Các types này cho biết nguồn gốc của tài nguyên và bạn có thể sử dụng chúng để xác định cách xử lý đối tượng phản hồi.

Khi trình duyệt yêu cầu một tài nguyên trên cùng một nguồn gốc, phản hồi sẽ có loại basic với các hạn chế về nội dung bạn có thể xem từ phản hồi.

Nếu một yêu cầu được thực hiện cho một tài nguyên trên một nguồn gốc khác và nguồn gốc đó trả về tiêu đề COR, thì loại đó sẽ là cors. Các phản hồi cors tương tự như phản hồi basic, nhưng hạn chế các tiêu đề mà bạn có thể xem ở Cache-Control, Content-Language, Content-Type, Expires, Last-ModifiedPragma.

Phản hồi opaque đến từ một nguồn gốc khác và không trả về tiêu đề CORS. Với phản hồi không rõ ràng, chúng tôi sẽ không thể đọc dữ liệu được trả về hoặc xem trạng thái của yêu cầu, nghĩa là bạn không thể kiểm tra xem yêu cầu có thành công hay không.

Bạn có thể xác định chế độ cho một yêu cầu tìm nạp để chỉ giải quyết một số loại yêu cầu nhất định. Bạn có thể đặt các chế độ như sau:

  • same-origin chỉ thành công các yêu cầu cho tài sản trên cùng một nguồn gốc và từ chối tất cả các yêu cầu khác.
  • cors cho phép yêu cầu thành phần có cùng nguồn gốc và các nguồn gốc khác trả về tiêu đề COR thích hợp.
  • cors-with-forced-preflight sẽ thực hiện quy trình kiểm tra trước khi trước khi đưa ra bất kỳ yêu cầu nào.
  • Mục đích của no-cors là gửi yêu cầu đến các nguồn gốc khác không có tiêu đề CORS và dẫn đến phản hồi opaque, nhưng như đã nêu , hiện tại hệ thống không thể thực hiện việc này trong phạm vi toàn hệ thống của cửa sổ.

Để xác định chế độ, hãy thêm một đối tượng tuỳ chọn làm tham số thứ hai trong yêu cầu fetch và xác định chế độ trong đối tượng đó:

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

Tạo chuỗi lời hứa

Một trong những tính năng tuyệt vời của lời hứa là khả năng liên kết chúng với nhau. Đối với fetch(), thao tác này cho phép bạn chia sẻ logic giữa các yêu cầu tìm nạp.

Nếu đang làm việc với API JSON, bạn cần kiểm tra trạng thái và phân tích cú pháp JSON cho từng phản hồi. Bạn có thể đơn giản hoá mã bằng cách xác định trạng thái và phân tích cú pháp JSON trong các hàm riêng biệt trả về lời hứa, đồng thời sử dụng yêu cầu tìm nạp để chỉ xử lý dữ liệu cuối cùng và trường hợp lỗi.

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(function(data) {
    console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
    console.log('Request failed', error);
    });

Ví dụ này xác định một hàm status kiểm tra response.status và trả về một Lời hứa đã phân giải dưới dạng Promise.resolve() hoặc một Lời hứa bị từ chối là Promise.reject(). Đây là phương thức đầu tiên được gọi trong chuỗi fetch().

Nếu Promise được giải quyết, thì tập lệnh sẽ gọi phương thức json(). Phương thức này sẽ trả về một Promise thứ hai từ lệnh gọi response.json() và tạo một đối tượng chứa JSON đã phân tích cú pháp. Nếu quá trình phân tích cú pháp không thành công, Promise sẽ bị từ chối và câu lệnh catch sẽ thực thi.

Cấu trúc này cho phép bạn chia sẻ logic trên tất cả các yêu cầu tìm nạp, giúp mã dễ bảo trì, đọc và kiểm thử hơn.

Yêu cầu POST

Đôi khi, ứng dụng web cần gọi một API bằng phương thức POST và đưa một số tham số vào phần nội dung của yêu cầu. Để thực hiện việc này, hãy đặt tham số methodbody trong các tuỳ chọn fetch():

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

Gửi thông tin đăng nhập kèm theo yêu cầu tìm nạp

Để tạo yêu cầu tìm nạp bằng thông tin xác thực như cookie, hãy đặt giá trị credentials của yêu cầu thành "include":

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