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

API tìm nạp() đang truy cập vào đối tượng cửa sổ và đang tìm cách thay thế XHR

XMLHttpRequest quá lâu

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, cho phép API đơn giản và rõ ràng hơn, tránh được lệnh gọi lại và phải nhớ API phức tạp của XMLHttpRequest.

Hỗ trợ trình duyệt

  • 42
  • 14
  • 39
  • 10.1

Nguồn

API Tìm nạp đã được cung cấp trong phạm vi toàn cầu của Service Worker kể từ Chrome 40 nhưng API này sẽ được bật trong phạm vi cửa sổ trên Chrome 42. Ngoài ra, còn có một polyfill by GitHub khác mà bạn có thể sử dụng ngay hôm nay để tìm nạp.

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

Hãy bắt đầu bằng cách so sánh một ví dụ đơn giản được triển khai với XMLHttpRequest và sau đó với fetch. Chúng tôi chỉ 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 thiết lập hai trình nghe để xử lý các trường hợp thành công và lỗi, đồng thời thực hiện lệnh gọi đến open()send(). Ví dụ trong 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 sẽ có dạng 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);
    });

Chúng tôi bắt đầu bằng cách kiểm tra để đảm bảo trạng thái phản hồi là 200 trước khi phân tích cú pháp phản hồi dưới dạng JSON.

Phản hồi của yêu cầu fetch() là một đối tượng Stream (Luồng), nghĩa là khi chúng ta gọi phương thức json(), một Promise sẽ được trả về vì quá trình đọc luồng sẽ xảy ra không đồng bộ.

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

Trong ví dụ trước, chúng ta đã xem trạng thái của đối tượng Response (Phản hồi), cũng như cách phân tích cú pháp phản hồi dưới dạng JSON. Siêu dữ liệu khác mà chúng ta có thể muốn truy cập, chẳng hạn như tiêu đề, được minh hoạ bên dưới.

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 một 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". types này cho biết nguồn gốc của tài nguyên và có thể dùng để thông báo cách bạn nên xử lý đối tượng phản hồi.

Khi yêu cầu được gửi đến 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à không có bất kỳ hạn chế nào về nội dung bạn có thể xem từ phản hồi.

Nếu yêu cầu được tạo cho một tài nguyên trên một nguồn gốc khác trả về tiêu đề COR, thì kiểu đó sẽ là cors. Các phản hồi corsbasic gần như giống hệt nhau ngoại trừ việc phản hồi cors giới hạn các tiêu đề mà bạn có thể xem thành Cache-Control, Content-Language, Content-Type, Expires, Last-ModifiedPragma.

Phản hồi opaque là dành cho 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 mà không trả về tiêu đề CORS. Với một phản hồi không rõ ràng, chúng ta sẽ không thể đọc dữ liệu được trả về hay xem trạng thái của yêu cầu, đồng nghĩa với việc chúng ta 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 yêu cầu tìm nạp sao cho chỉ một số yêu cầu nhất định mới được giải quyết. Bạn có thể đặt các chế độ như sau:

  • same-origin chỉ thành công các yêu cầu về tài sản trên cùng một nguồn gốc, tất cả các yêu cầu khác sẽ từ chối.
  • cors sẽ cho phép các yêu cầu đối với 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ẽ luôn thực hiện kiểm tra trước khi kiểm tra trước khi đưa ra yêu cầu thực tế.
  • 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 bạn không thể làm điều 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)
    });

Lời hứa hẹn chuỗi

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. Để tìm nạp, điều 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ã của mình 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, như vậy bạn sẽ không phải lo lắng về việc xử lý dữ liệu cuối cùng và trường hợp lỗi nữa.

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);
    });

Chúng ta xác định hàm status kiểm tra response.status và trả về kết quả của Promise.resolve() hoặc Promise.reject() trả về một Lời hứa đã được giải quyết hoặc bị từ chối. Đây là phương thức đầu tiên được gọi trong chuỗi fetch(). Nếu giải quyết được, chúng ta sẽ gọi phương thức json() để trả về một Promise từ lệnh gọi response.json(). Sau đó, chúng ta có một đối tượng 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.

Điều tuyệt vời là bạn có thể chia sẻ logic trên mọi yêu cầu tìm nạp, giúp duy trì, đọc và kiểm thử mã dễ dàng hơn.

Yêu cầu POST

Các ứng dụng web thường muốn gọi một API bằng phương thức POST và cung cấp một số tham số trong phần nội dung của yêu cầu.

Để làm điều này, chúng ta có thể đặt các 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 xác thực có yêu cầu tìm nạp

Nếu muốn tạo yêu cầu tìm nạp bằng các thông tin xác thực như cookie, bạn nên đặt credentials của yêu cầu thành "include".

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

Câu hỏi thường gặp

Làm cách nào để huỷ yêu cầu tìm nạp()?

Hiện tại không có cách nào để huỷ quá trình tìm nạp, nhưng điều này đang được thảo luận trên GitHub. H/T @jaffathecupcake cho đường liên kết này.

Có vải polyfill không?

GitHub có một polyfill để tìm nạp. H/T @Nexii đã chỉ ra điều này.

Tại sao tuỳ chọn "no-cors" (không có cor) được hỗ trợ trong trình chạy dịch vụ nhưng không được hỗ trợ trong cửa sổ?

Điều này là do mối lo ngại về bảo mật, bạn có thể tìm hiểu thêm tại đây.