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

Bài viết này minh hoạ một số phương pháp xử lý lỗi khi làm việc với Fetch API. 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 lệnh gọi mạng từ xa, trang web của bạn có thể gặp nhiều lỗi mạng.

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

Phần này mô tả 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", sau đó tìm cách tải video đó lên một trang web chia sẻ video.

Khi sử dụng Tìm nạp, bạn có thể dễ dàng xem xét đường dẫn hài lòng mà 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ẻ như vậy nhưng nhà phát triển web phải lên kế hoạch. Những đường dẫn (không mong muốn) như vậy có thể xảy ra do lỗi của người dùng, do đ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 (chẳng hạn như JPEG) lên thay vì tệp video.
  • Người dùng bắt đầu tải tệp video không đúng lên. Sau đó, 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 "Huỷ tải lên" trong khi video đang tải lên.

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

  • Kết nối Internet bị ngắt trong khi tải video lên.
  • Trình duyệt khởi động lại trong khi tải video lên.
  • Máy chủ của trang web chia sẻ video 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ó khoảng trắng. Thay vì "My Travels.mp4", thành phần này yêu cầu tên chẳng hạn như "My_Travels.mp4" hoặc "MyTravels.mp4".
  • Trang web chia sẻ video không thể tải video lên vì 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 bạn tải lên.

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

  • Hành vi mặc định là gì nếu dịch vụ chia sẻ video không thể xử lý ví dụ đã cho?
  • Người dùng mong đợi điều gì sẽ xảy ra trong ví dụ này?
  • Chúng tôi có thể cải thiện quy trình này bằng cách nào?
Hành động Người dùng bắt đầu tải tệp video không đúng lên. Sau đó, 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ì sẽ xảy ra theo mặc định Tệp gốc sẽ tiếp tục tải lên ở chế độ nền trong khi tệp mới tải lên cùng lúc.
Điều người dùng mong đợi Người dùng muốn quá trình tải lên ban đầu dừng lại để không lãng phí băng thông Internet.
Những điểm có thể cải thiện JavaScript huỷ yêu cầu Tìm nạp cho tệp gốc 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 một phần khi tải video lên.
Điều gì xảy ra theo mặc định Thanh tiến trình tải lên có vẻ như bị treo ở mức 50%. Cuối cùng, Fetch API sẽ hết thời gian chờ và dữ liệu đã 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.
Điều người dùng mong đợi Người dùng muố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 họ có kết nối mạng trở lại.
Những điểm có thể cải thiện Trang tải lên sẽ thông báo cho người dùng về các vấn đề liên quan đến kết nối Internet và giúp người dùng yên tâm rằng quá trình tải lên sẽ tiếp tục khi có 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ó khoảng trắng. Thay vì "My Travels.mp4", bạn nên đặt 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ệp được tải lên và thanh tiến trình hiển thị "100%", thanh tiến trình sẽ hiển thị thông báo: "Vui lòng thử lại".
Điều người dùng mong đợi Người dùng muốn được thông báo về các giới hạn về 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 của quá trình tải lên.
Những điểm có thể cải thiện Tốt nhất là dịch vụ chia sẻ video hỗ trợ tên tệp có dấu cách. Bạn cũng có thể thông báo cho người dùng về các giới hạn về 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 yêu cầu 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 ví dụ về mã 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 Fetch API 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 gửi trong khối try. Ví dụ: nếu API Tìm nạp không thể tìm nạp tài nguyên đã chỉ định, thì hệ thống sẽ báo lỗi. Trong một khối catch như thế này, hãy cẩn thận để mang lại trải nghiệm có ý nghĩa cho người dùng. Nếu vòng quay (một giao diện người dùng phổ biến đại diện cho một số tiến trình) hiển thị với người dùng, thì bạn có thể thực hiện các thao tác sau trong khối catch:

  1. Xoá trình đơn vòng quay khỏi trang.
  2. Cung cấp thông báo hữu ích giải thích vấn đề đã xảy ra và những lựa chọn mà người dùng có thể thực hiện.
  3. Dựa trên các tuỳ chọn có sẵn, hãy hiển thị nút "Thử lại" cho người dùng.
  4. Ở chế độ nền, hãy gửi thông tin chi tiết về lỗi đến dịch vụ theo dõi lỗi hoặc đến phần phụ trợ. Thao tác này sẽ ghi lại lỗi để có thể chẩn đoán sau này.
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 một trường hợp kiểm thử để phát hiện lỗi đó trước khi người dùng nhận thấy có gì đó không ổn. 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 biểu thị lỗi

Mã ví dụ này gửi yêu cầu đến 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 đế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à thay vào đó sẽ phân giải bình thường.

Để kiểm tra xem mã trạng thái HTTP đã thành công hay chưa, 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 phạm vi 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 siêu dữ liệu bất kỳ 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}`)
}

Tốt nhất là bạn nên làm việc với những người trong tổ chức và nhóm của mình để tìm hiểu các mã trạng thái phản hồi HTTP có thể xảy ra. Đôi khi, các nhà phát triển phụ trách phần phụ trợ, hoạt động của nhà phát triển và kỹ sư dịch vụ 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 có thể 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ể xảy ra 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 các loại dữ liệu khác nhau, 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 một dịch vụ kiểm thử HTTP trả về một chuỗi HTML làm 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, dẫn đến 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ã để tiếp nhận nhiều định dạng phản hồi và xác minh rằng phản hồi không mong muốn không phá vỡ 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 này được phân tích cú pháp thành công bằng phương thức Response.json(). Dịch vụ có thể bị ngừng. Sau khi gỡ lỗi, 500 Internal Server Error sẽ được trả về. Nếu kỹ thuật xử lý lỗi thích hợp không được sử dụng trong quá trình phân tích cú pháp JSON, điều này có thể làm hỏng trang cho người dùng vì hệ thống sẽ gửi lỗi không được xử lý.

Trường hợp bạn phải huỷ yêu cầu kết nối mạng 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 thực hiện. Yêu cầu đang diễn ra 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ần huỷ yêu cầu đang diễn ra có thể khác nhau, nhưng sau cùng còn 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 truyền AbortSignal đến API Tìm nạp. AbortSignal được đính kèm vào AbortControllerAbortController bao gồm phương thức abort(), cho trình duyệt biết rằng yêu cầu mạng sẽ bị 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 việc xử lý lỗi là xác định các phần có thể gặp lỗi. Đối với mỗi trường hợp, hãy đảm bảo bạn có phương án dự phòng phù hợp cho người dùng. Đối với yêu cầu tìm nạp, hãy tự đặt ra những câu hỏi như:

  • Điều gì xảy ra nếu máy chủ mục tiêu ngừng hoạt động?
  • Điều gì sẽ xảy ra nếu Fetch nhận được phản hồi không mong muốn?
  • Điều gì sẽ xảy ra nếu kết nối Internet của người dùng không thành công?

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