fetch() cho phép bạn tạo các yêu cầu mạng tương tự như XMLHttpRequest (XHR). Sự khác biệt chính là Fetch API sử dụng Promises, có 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 XMLHttpRequest API.
Nếu bạn chưa từng sử dụng Lời hứa, hãy xem bài viết Giới thiệu về Lời hứa trong JavaScript.
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 đó là 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 phản hồi đó 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, đồng thời gọi open() và send().
Ví dụ trong tài liệu 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();
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(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);
});
Yêu cầu fetch() chỉ cần một lệnh gọi để thực hiện cùng một công việc như ví dụ về XHR. Để xử lý phản hồi, trước tiên, chúng ta kiểm tra xem trạng thái phản hồi có phải là 200 hay không, 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à một đối tượng Stream, nghĩa là sau khi chúng ta gọi phương thức json(), một Promise sẽ được trả về.
Luồng này diễn ra không đồng bộ.
Siêu dữ liệu phản hồi
Ví dụ trước cho thấy trạng thái của đối tượng Response và cách phân tích cú pháp phản hồi dưới dạng JSON. Sau đâ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(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 ta đưa ra yêu cầu tìm nạp, phản hồi sẽ được cung cấp response.type
của "basic",
"cors" hoặc
"opaque".
types này cho biết tài nguyên đến từ đâu 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 kèm theo các quy định hạn chế về nội dung bạn có thể xem trong 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 là cors. Phản hồi cors tương tự như phản hồi basic, nhưng chúng hạn chế các tiêu đề mà bạn có thể xem thành Cache-Control, Content-Language, Content-Type, Expires, Last-Modified và Pragma.
opaque phản hồi đến từ một nguồn gốc khác không trả về tiêu đề CORS. Với phản hồi mờ, 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 một chế độ cho yêu cầu tìm nạp để chỉ một số loại yêu cầu nhất định được giải quyết. Bạn có thể đặt các chế độ như sau:
same-originchỉ thành công đối với các yêu cầu về thành phầ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.corscho phép các yêu cầu về tài sản trên cùng một 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-preflightthực hiện kiểm tra trước trước khi đưa ra yêu cầu.no-corsdùng để 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ồiopaque, nhưng như đã nêu , điều này hiện không thể thực hiện được trong phạm vi toàn cục 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(response => response.text())
.then(text => {
console.log('Request successful', text);
})
.catch(error => {
log('Request failed', error)
});
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(), đ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 một API JSON, bạn cần kiểm tra trạng thái và phân tích cú pháp JSON cho mỗi 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(data => {
console.log('Request succeeded with JSON response', data);
}).catch(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 Promise đã phân giải dưới dạng Promise.resolve() hoặc một Promise bị từ chối dưới dạng Promise.reject().
Đây là phương thức đầu tiên được gọi trong chuỗi fetch().
Nếu Lời hứa được thực hiện, thì tập lệnh sẽ gọi phương thức json(). Phương thức này trả về Lời hứa thứ hai từ lệnh gọi response.json() và tạo một đối tượng chứa JSON được 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ễ duy 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 nội dung của yêu cầu. Để thực hiện việc này, hãy đặt các tham số method và body 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(data => {
console.log('Request succeeded with JSON response', data);
})
.catch(error => {
console.log('Request failed', error);
});
Gửi thông tin đăng nhập bằng 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 (chẳng hạn như cookie), hãy đặt giá trị credentials của yêu cầu thành "include":
fetch(url, {
credentials: 'include'
})