Fetch API là một giao diện lập trình ứng dụng (API) hiện đại và mạnh mẽ trong Javascript, được sử dụng để thực hiện các yêu cầu (request) HTTP đến máy chủ và nhận về các phản hồi (response). Nó cung cấp một cách tiếp cận linh hoạt và dễ sử dụng hơn so với XMLHttpRequest (XHR) truyền thống, đặc biệt trong việc làm việc với các promise và xử lý bất đồng bộ. Với Fetch API, việc truy xuất dữ liệu từ server, gửi dữ liệu lên server hoặc tương tác với các API web trở nên đơn giản và hiệu quả hơn rất nhiều.
Bạn có thể dễ dàng kiểm tra xem trình duyệt web bạn đang sử dụng có hỗ trợ Fetch API hay không bằng đoạn mã Javascript sau:
if (!('fetch' in window)) {
console.log('Trình duyệt của bạn không hỗ trợ Fetch API.');
} else {
console.log('Trình duyệt của bạn hỗ trợ Fetch API.');
// Bạn có thể sử dụng Fetch API từ bây giờ
}
Đoạn mã trên kiểm tra sự tồn tại của đối tượng fetch
trong đối tượng window
toàn cục. Nếu fetch
không tồn tại, điều đó có nghĩa là trình duyệt không hỗ trợ Fetch API và bạn có thể cần sử dụng polyfill (thư viện bổ sung chức năng) để hỗ trợ các trình duyệt cũ hơn.
Phương thức fetch()
là trái tim của Fetch API. Nó nhận vào đối số đầu tiên là URL mà bạn muốn gửi yêu cầu đến. Phương thức này trả về một Promise, và promise này sẽ “resolve” (thành công) khi máy chủ phản hồi yêu cầu, bất kể mã trạng thái HTTP của phản hồi là gì (ví dụ: 200 OK, 404 Not Found, 500 Internal Server Error).
Khởi tạo một Fetch Request
Hãy cùng xem xét một ví dụ cơ bản về cách sử dụng fetch()
để lấy dữ liệu từ một file JSON:
fetch('examples/example.json')
.then(function(response) {
// Xử lý phản hồi ở đây
})
.catch(function(error) {
console.log('Đã xảy ra lỗi trong quá trình fetch: n', error);
});
Trong ví dụ này, chúng ta gọi hàm fetch()
với đường dẫn 'examples/example.json'
. Hàm fetch()
sẽ gửi một yêu cầu HTTP GET đến URL này. Khi máy chủ trả về phản hồi, promise trả về từ fetch()
sẽ resolve và hàm callback trong .then()
sẽ được thực thi, nhận đối tượng response
làm tham số. Nếu có bất kỳ lỗi nào xảy ra trong quá trình gửi yêu cầu (ví dụ: mất kết nối mạng), promise sẽ reject và hàm callback trong .catch()
sẽ được gọi, nhận đối tượng error
mô tả lỗi.
Đối tượng response
chứa toàn bộ thông tin phản hồi từ máy chủ, bao gồm cả dữ liệu trả về và các thông tin metadata khác như headers, status code, và status text. Để kiểm tra xem yêu cầu có thành công hay không, bạn có thể sử dụng thuộc tính response.ok
. Thuộc tính này trả về true
nếu mã trạng thái HTTP nằm trong khoảng 200-299 (thường biểu thị thành công), và false
trong các trường hợp khác (ví dụ: 404 Not Found, 500 Internal Server Error). Các thuộc tính khác như response.status
(mã trạng thái HTTP) và response.statusText
(mô tả trạng thái HTTP) cũng rất hữu ích để đánh giá kết quả của yêu cầu.
Một điểm quan trọng cần lưu ý khi sử dụng Fetch API là kể cả khi máy chủ trả về lỗi (ví dụ: mã trạng thái 404), promise từ fetch()
vẫn sẽ resolve chứ không reject. Promise chỉ reject trong trường hợp lỗi mạng hoặc các lỗi ngăn chặn việc hoàn thành request ở tầng thấp hơn. Do đó, việc kiểm tra trạng thái phản hồi là rất quan trọng để đảm bảo xử lý đúng các tình huống lỗi. Đoạn code sau minh họa cách kiểm tra response.ok
để xử lý các trường hợp lỗi HTTP:
fetch('examples/example.json')
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText); // Nếu response.ok là false, ném ra lỗi
}
// Xử lý phản hồi thành công ở đây
})
.catch(function(error) {
console.log('Đã xảy ra lỗi: n', error);
});
Trong đoạn code cập nhật này, chúng ta kiểm tra response.ok
trong hàm callback của .then()
. Nếu response.ok
là false
, chúng ta chủ động ném ra một đối tượng Error
với thông báo lỗi là response.statusText
. Điều này sẽ khiến promise bị reject và chuyển đến hàm callback của .catch()
, giúp chúng ta xử lý các lỗi HTTP một cách rõ ràng.
Đọc nội dung phản hồi (Response Body)
Đối tượng response
cung cấp nhiều phương thức để truy cập vào nội dung (body) của phản hồi, tùy thuộc vào định dạng dữ liệu trả về từ máy chủ. Ví dụ:
response.json()
: Trả về một promise resolve thành một đối tượng Javascript sau khi phân tích cú pháp (parse) nội dung phản hồi dưới dạng JSON. Thường được sử dụng khi làm việc với các API web trả về dữ liệu JSON.response.text()
: Trả về một promise resolve thành nội dung phản hồi dưới dạng chuỗi văn bản (text).response.blob()
: Trả về một promise resolve thành nội dung phản hồi dưới dạng Blob object, thường được sử dụng để xử lý dữ liệu nhị phân như hình ảnh hoặc file.response.formData()
: Trả về một promise resolve thành nội dung phản hồi dưới dạng FormData object, thường được sử dụng khi làm việc với dữ liệu form HTML.response.arrayBuffer()
: Trả về một promise resolve thành nội dung phản hồi dưới dạng ArrayBuffer object, biểu diễn dữ liệu nhị phân ở dạng bộ đệm byte.
Để tiếp tục ví dụ trước và xử lý dữ liệu JSON trả về từ 'examples/example.json'
, chúng ta sẽ sử dụng phương thức response.json()
:
fetch('examples/example.json')
.then(function(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json(); // Đọc response body dưới dạng JSON và trả về một promise
})
.then(function(responseAsJson) {
// Xử lý dữ liệu JSON ở đây
console.log(responseAsJson);
})
.catch(function(error) {
console.log('Đã xảy ra lỗi: n', error);
});
Trong ví dụ trên, sau khi kiểm tra response.ok
, chúng ta gọi response.json()
. Phương thức này trả về một promise khác, promise này sẽ resolve thành đối tượng JSON sau khi dữ liệu được tải xuống và phân tích cú pháp thành công. Hàm callback thứ hai trong chuỗi .then()
sẽ nhận đối tượng JSON này (responseAsJson
) làm tham số, và chúng ta có thể xử lý dữ liệu JSON này ở bước này.
Để code trở nên dễ đọc và dễ bảo trì hơn, chúng ta có thể tách các bước xử lý thành các hàm riêng biệt:
function logResult(result) {
console.log(result);
}
function logError(error) {
console.log('Đã xảy ra lỗi: n', error);
}
function validateResponse(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
function readResponseAsJSON(response) {
return response.json();
}
function fetchJSON(pathToResource) {
fetch(pathToResource) // Bước 1
.then(validateResponse) // Bước 2
.then(readResponseAsJSON) // Bước 3
.then(logResult) // Bước 4
.catch(logError);
}
fetchJSON('examples/example.json');
Tóm tắt quy trình Fetch API trong ví dụ trên:
- Bước 1:
fetch(pathToResource)
: Gửi yêu cầu fetch đến URLexamples/example.json
. Hàmfetch()
trả về một promise. Khi phản hồi từ server được nhận (kể cả lỗi HTTP), promise này resolve và giá trị resolve là đối tượngresponse
. Giá trị này được truyền cho hàmvalidateResponse
trong bước tiếp theo. - Bước 2:
.then(validateResponse)
: HàmvalidateResponse
nhận đối tượngresponse
từ bước trước. Hàm này kiểm traresponse.ok
để xác định xem yêu cầu HTTP có thành công hay không (mã trạng thái 2xx). Nếu không thành công, hàm này ném ra một lỗi, khiến promise bị reject và quy trình chuyển đến.catch(logError)
. Nếu thành công, hàm này trả về đối tượngresponse
cho bước tiếp theo. - Bước 3:
.then(readResponseAsJSON)
: HàmreadResponseAsJSON
nhận đối tượngresponse
(đã được xác thực là thành công ở bước trước). Hàm này gọiresponse.json()
để đọc body của response dưới dạng JSON.response.json()
cũng trả về một promise, promise này resolve thành đối tượng JSON sau khi phân tích cú pháp thành công. Giá trị JSON này được truyền cho hàmlogResult
ở bước tiếp theo. - Bước 4:
.then(logResult)
: HàmlogResult
nhận dữ liệu JSON từ bước trước và đơn giản là in dữ liệu này ra console. .catch(logError)
: Nếu bất kỳ promise nào trong chuỗi promise trên bị reject (ví dụ: lỗi mạng, lỗi HTTP không thành công, lỗi parse JSON), hàmlogError
sẽ được gọi để xử lý lỗi và in thông tin lỗi ra console.
Fetch API là một công cụ mạnh mẽ và linh hoạt cho việc thực hiện các yêu cầu web trong Javascript. Việc nắm vững cách sử dụng Fetch API là rất quan trọng đối với bất kỳ nhà phát triển web nào muốn xây dựng các ứng dụng web hiện đại và tương tác với dữ liệu từ server một cách hiệu quả.