Triển khai khả năng xử lý lỗi khi sử dụng Fetch API

Bài viết này trình bày một số phương pháp xử lý lỗi khi làm việc với API Tìm nạp. API Tìm nạp cho phép bạn gửi yêu cầu đến một tài nguyên mạng từ xa. Khi bạn thực hiện một cuộc gọi mạng từ xa, trang web của bạn sẽ gặp phải nhiều lỗi mạng có thể xảy ra.

Các phần sau đây mô tả các lỗi có thể xảy ra và mô tả cách viết mã cung cấp chức năng hợp lý có khả năng thích ứng với lỗi và điều kiện mạng không mong muốn. Mã có khả năng chống chịu giúp người dùng hài lòng và duy trì cấp dịch vụ tiêu chuẩn cho trang web của bạn.

Dự đoán các lỗi mạng có thể xảy ra

Phần này mô tả tình huống trong đó người dùng tạo một video mới có tên là "My Travels.mp4" rồi cố tải video đó lên một trang web chia sẻ video.

Khi làm việc với Tìm nạp, bạn có thể dễ dàng xem xét đường dẫn hạnh phúc nơi người dùng tải video lên thành công. Tuy nhiên, có những lộ trình khác không suôn sẻ mà các nhà phát triển web phải lên kế hoạch. Các đường dẫn (không vui) như vậy có thể xảy ra do lỗi người dùng, thông qua các điều kiện môi trường không mong muốn hoặc do lỗi trên trang web chia sẻ video.

Ví dụ về lỗi người dùng

  • Người dùng tải tệp hình ảnh lên (chẳng hạn như JPEG) thay vì tệp video.
  • Người dùng bắt đầu tải sai tệp video lên. Trong quá trình tải lên, người dùng chỉ định đúng tệp video để tải lên.
  • Người dùng vô tình nhấp vào "Hủy tải lên" trong khi video đang tải lên.

Ví dụ về những thay đổi về môi trường

  • Kết nối Internet bị ngắt kết nối trong khi video đang tải lên.
  • Trình duyệt sẽ khởi động lại trong lúc video đang tải lên.
  • Máy chủ của trang web chia sẻ video sẽ khởi động lại trong khi video đang tải lên.

Ví dụ về lỗi với trang web chia sẻ video

  • Trang web chia sẻ video không thể xử lý tên tệp có dấu cách. Thay vì "My Travels.mp4", lớp này sẽ nhận một tên như "My_Travels.mp4" hoặc "MyTravels.mp4".
  • Trang web chia sẻ video không thể tải lên video vượt quá kích thước tệp tối đa được chấp nhận.
  • Trang web chia sẻ video không hỗ trợ bộ mã hoá và giải mã video trong video được tải lên.

Những ví dụ này có thể và xảy ra trong thực tế. Có thể bạn đã từng gặp những trường hợp như vậy! Hãy chọn một ví dụ từ mỗi danh mục trước và thảo luận về các điểm sau:

  • Đâu là hành vi mặc định nếu dịch vụ chia sẻ video không thể xử lý ví dụ đã nêu?
  • Người dùng mong đợi điều gì sẽ xảy ra trong ví dụ này?
  • Chúng tôi có thể làm gì để cải thiện quy trình này?
Hành động Người dùng bắt đầu tải sai tệp video lên. Trong quá trình tải lên, người dùng chỉ định đúng tệp video để tải lên.
Điều gì xảy ra theo mặc định Tệp gốc tiếp tục được tải lên trong nền trong khi tệp mới được tải lên cùng lúc.
Những gì người dùng mong đợi Người dùng muốn dừng tải lên ban đầu để không lãng phí thêm băng thông Internet.
Những điểm cần cải thiện JavaScript sẽ huỷ yêu cầu Tìm nạp cho tệp ban đầu trước khi tệp mới bắt đầu tải lên.
Hành động Người dùng mất kết nối Internet trong lúc tải video lên.
Điều gì xảy ra theo mặc định Có vẻ như thanh tiến trình tải lên bị treo ở mức 50%. Cuối cùng, API Tìm nạp sẽ hết thời gian chờ và dữ liệu được tải lên sẽ bị loại bỏ. Khi kết nối Internet trở lại, người dùng phải tải tệp lên lại.
Những gì người dùng mong đợi Người dùng muốn nhận được thông báo khi không thể tải tệp lên, và họ muốn quá trình tải lên tự động tiếp tục ở mức 50% khi có kết nối mạng trở lại.
Những điểm cần cải thiện Trang tải lên thông báo cho người dùng về các sự cố kết nối Internet và đảm bảo với người dùng rằng quá trình tải lên sẽ tiếp tục khi kết nối Internet tiếp tục.
Hành động Trang web chia sẻ video không thể xử lý tên tệp có dấu cách. Thay vì "My Travels.mp4", thẻ này sẽ nhận các tên như "My_Travels.mp4" hoặc "MyTravels.mp4".
Điều gì xảy ra theo mặc định Người dùng phải đợi quá trình tải lên hoàn tất. Sau khi tải tệp lên và thanh tiến trình hiển thị "100%", thanh tiến trình hiển thị thông báo: "Vui lòng thử lại".
Những gì người dùng mong đợi Người dùng muốn được thông báo về giới hạn của tên tệp trước khi bắt đầu tải lên hoặc ít nhất là trong giây đầu tiên sau khi tải lên.
Những điểm cần cải thiện Tốt nhất là dịch vụ chia sẻ video sẽ hỗ trợ tên tệp có dấu cách. Lựa chọn thay thế là thông báo cho người dùng về giới hạn của tên tệp trước khi bắt đầu tải lên. Hoặc dịch vụ chia sẻ video sẽ từ chối tải lên kèm theo thông báo lỗi chi tiết.

Xử lý lỗi bằng API Tìm nạp

Xin lưu ý rằng các mã ví dụ sau đây sử dụng await cấp cao nhất (hỗ trợ trình duyệt) vì tính năng này có thể đơn giản hoá mã của bạn.

Khi API Tìm nạp gửi lỗi

Ví dụ này sử dụng câu lệnh khối try/catch để phát hiện mọi lỗi được tạo ra trong khối try. Ví dụ: nếu API Tìm nạp không thể tìm nạp tài nguyên được chỉ định, thì hệ thống sẽ báo lỗi. Trong khối catch như thế này, hãy chú ý cung cấp trải nghiệm người dùng có ý nghĩa. Nếu người dùng thấy một vòng quay (giao diện người dùng phổ biến đại diện cho một loại tiến trình nào đó), thì bạn có thể thực hiện các thao tác sau trong khối catch:

  1. Xoá vòng quay này khỏi trang.
  2. Đưa ra thông báo hữu ích để giải thích lỗi và những lựa chọn mà người dùng có thể chọn.
  3. Dựa vào các lựa chọn có sẵn, hãy cho người dùng thấy nút "Thử lại".
  4. Trong hậu trường, hãy gửi thông tin chi tiết về lỗi cho dịch vụ theo dõi lỗi hoặc dịch vụ hỗ trợ. Thao tác này sẽ ghi lại lỗi để có thể chẩn đoán ở giai đoạn sau.
try {
  const response = await fetch('https://website');
} catch (error) {
  // TypeError: Failed to fetch
  console.log('There was an error', error);
}

Ở giai đoạn sau, trong khi chẩn đoán lỗi mà bạn đã ghi lại, bạn có thể viết trường hợp kiểm thử để phát hiện lỗi như vậy trước khi người dùng biết đã xảy ra lỗi. Tuỳ thuộc vào lỗi, kiểm thử có thể là kiểm thử đơn vị, kiểm thử tích hợp hoặc kiểm thử chấp nhận.

Khi mã trạng thái mạng báo lỗi

Ví dụ về mã này gửi yêu cầu tới một dịch vụ kiểm thử HTTP luôn phản hồi bằng mã trạng thái HTTP 429 Too Many Requests. Điều thú vị là phản hồi không tiếp cận được khối catch. Trạng thái 404, cùng với một số mã trạng thái khác, không trả về lỗi mạng mà giải quyết bình thường.

Để kiểm tra xem mã trạng thái HTTP có thành công hay không, bạn có thể sử dụng bất kỳ tuỳ chọn nào sau đây:

  • Sử dụng thuộc tính Response.ok để xác định xem mã trạng thái có nằm trong khoảng từ 200 đến 299 hay không.
  • Sử dụng thuộc tính Response.status để xác định xem phản hồi có thành công hay không.
  • Sử dụng bất kỳ siêu dữ liệu nào khác, chẳng hạn như Response.headers, để đánh giá xem phản hồi có thành công hay không.
let response;

try {
  response = await fetch('https://httpbin.org/status/429');
} catch (error) {
  console.log('There was an error', error);
}

// Uses the 'optional chaining' operator
if (response?.ok) {
  console.log('Use the response here!');
} else {
  console.log(`HTTP Response Code: ${response?.status}`)
}

Cách tốt nhất là làm việc với mọi người trong tổ chức và nhóm của bạn để hiểu các mã trạng thái phản hồi HTTP tiềm năng. Nhà phát triển phụ trợ, kỹ sư vận hành của nhà phát triển và kỹ sư dịch vụ đôi khi có thể cung cấp thông tin chi tiết độc đáo về các trường hợp hiếm gặp mà bạn không lường trước được.

Khi xảy ra lỗi khi phân tích cú pháp phản hồi mạng

Ví dụ về mã này minh hoạ một loại lỗi khác có thể phát sinh khi phân tích cú pháp nội dung phản hồi. Giao diện Response cung cấp các phương thức thuận tiện để phân tích cú pháp nhiều loại dữ liệu, chẳng hạn như văn bản hoặc JSON. Trong mã sau, một yêu cầu mạng được gửi đến dịch vụ kiểm thử HTTP trả về một chuỗi HTML dưới dạng nội dung phản hồi. Tuy nhiên, hệ thống sẽ cố gắng phân tích cú pháp nội dung phản hồi dưới dạng JSON và gửi ra một lỗi.

let json;

try {
  const response = await fetch('https://httpbin.org/html');
  json = await response.json();
} catch (error) {
  if (error instanceof SyntaxError) {
    // Unexpected token < in JSON
    console.log('There was a SyntaxError', error);
  } else {
    console.log('There was an error', error);
  }
}

if (json) {
  console.log('Use the JSON here!', json);
}

Bạn phải chuẩn bị mã để chấp nhận nhiều định dạng phản hồi và xác minh rằng một phản hồi không mong muốn không làm hỏng trang web cho người dùng.

Hãy xem xét trường hợp sau: Bạn có một tài nguyên từ xa trả về phản hồi JSON hợp lệ và tài nguyên đó được phân tích cú pháp thành công bằng phương thức Response.json(). Có thể dịch vụ ngừng hoạt động. Sau khi thanh toán xuống, hàm 500 Internal Server Error sẽ được trả về. Nếu bạn không sử dụng các kỹ thuật xử lý lỗi thích hợp trong quá trình phân tích cú pháp JSON, thì điều này có thể khiến trang bị hỏng cho người dùng do xảy ra lỗi không được xử lý.

Khi yêu cầu kết nối mạng phải bị huỷ trước khi hoàn tất

Ví dụ về mã này sử dụng AbortController để huỷ một yêu cầu đang được tiến hành. Yêu cầu đang tiến hành là một yêu cầu mạng đã bắt đầu nhưng chưa hoàn tất.

Các trường hợp bạn có thể cần phải huỷ một yêu cầu đang được tiến hành có thể khác nhau, nhưng cuối cùng điều này phụ thuộc vào trường hợp sử dụng và môi trường của bạn. Mã sau đây minh hoạ cách chuyển AbortSignal đến API Tìm nạp. AbortSignal được đính kèm vào AbortControllerAbortController bao gồm một phương thức abort(), cho trình duyệt biết rằng yêu cầu mạng cần được huỷ.

const controller = new AbortController();
const signal = controller.signal;

// Cancel the fetch request in 500ms
setTimeout(() => controller.abort(), 500);

try {
  const url = 'https://httpbin.org/delay/1';
  const response = await fetch(url, { signal });
  console.log(response);
} catch (error) {
  // DOMException: The user aborted a request.
  console.log('Error: ', error)
}

Kết luận

Một khía cạnh quan trọng trong quá trình xử lý lỗi là xác định các phần có thể xảy ra lỗi. Đối với mỗi trường hợp, hãy đảm bảo bạn có một phương án dự phòng thích hợp cho người dùng. Đối với yêu cầu tìm nạp, hãy tự đặt ra các câu hỏi như:

  • Điều gì sẽ xảy ra nếu máy chủ đích ngừng hoạt động?
  • Điều gì xảy ra nếu Tìm nạp nhận được phản hồi không mong muốn?
  • Điều gì xảy ra nếu kết nối Internet của người dùng bị lỗi?

Tuỳ thuộc vào độ phức tạp của trang web, bạn cũng có thể phác thảo sơ đồ quy trình mô tả chức năng và giao diện người dùng trong các tình huống khác nhau.