ใช้การจัดการข้อผิดพลาดเมื่อใช้ Fetch API

บทความนี้จะสาธิตวิธีการจัดการข้อผิดพลาดบางอย่างเมื่อทำงานกับ Fetch API API ดึงข้อมูลช่วยให้คุณสามารถส่งคำขอไปยังทรัพยากรเครือข่ายระยะไกลได้ เมื่อคุณเรียกใช้เครือข่ายจากระยะไกล หน้าเว็บอาจเกิดข้อผิดพลาดเกี่ยวกับเครือข่ายได้หลายประการ

ส่วนต่อไปนี้จะอธิบายข้อผิดพลาดที่อาจเกิดขึ้นและอธิบายวิธีเขียนโค้ดที่มอบฟังก์ชันการทำงานในระดับที่เหมาะสมซึ่งทนต่อข้อผิดพลาดและสภาพเครือข่ายที่ไม่คาดคิด โค้ดที่ยืดหยุ่นช่วยให้ผู้ใช้พึงพอใจและรักษาระดับการบริการมาตรฐานสำหรับเว็บไซต์

คาดการณ์ข้อผิดพลาดที่อาจเกิดขึ้นกับเครือข่าย

ส่วนนี้จะอธิบายสถานการณ์ที่ผู้ใช้สร้างวิดีโอใหม่ชื่อ "My Travels.mp4" แล้วพยายามอัปโหลดวิดีโอไปยังเว็บไซต์แชร์วิดีโอ

เมื่อใช้การดึงข้อมูล คุณควรพิจารณาเส้นทางที่ใช้ได้อย่างราบรื่นซึ่งผู้ใช้อัปโหลดวิดีโอได้สำเร็จ อย่างไรก็ตาม ยังมีเส้นทางอื่นๆ ที่อาจไม่ราบรื่นนัก แต่นักพัฒนาเว็บต้องวางแผนไว้ เส้นทาง (ที่ไม่พึงพอใจ) ดังกล่าวอาจเกิดขึ้นจากข้อผิดพลาดของผู้ใช้ สภาพแวดล้อมที่ไม่คาดคิด หรือข้อบกพร่องในเว็บไซต์แชร์วิดีโอ

ตัวอย่างข้อผิดพลาดของผู้ใช้

  • ผู้ใช้อัปโหลดไฟล์ภาพ (เช่น JPEG) แทนไฟล์วิดีโอ
  • ผู้ใช้เริ่มอัปโหลดไฟล์วิดีโอที่ไม่ถูกต้อง จากนั้นระหว่างการอัปโหลด ผู้ใช้ระบุไฟล์วิดีโอที่ถูกต้องสำหรับการอัปโหลด
  • ผู้ใช้คลิก "ยกเลิกการอัปโหลด" โดยไม่ได้ตั้งใจขณะที่อัปโหลดวิดีโอ

ตัวอย่างการเปลี่ยนแปลงด้านสิ่งแวดล้อม

  • การเชื่อมต่ออินเทอร์เน็ตออฟไลน์ขณะอัปโหลดวิดีโอ
  • เบราว์เซอร์รีสตาร์ทขณะที่อัปโหลดวิดีโอ
  • เซิร์ฟเวอร์ของเว็บไซต์แชร์วิดีโอรีสตาร์ทขณะที่อัปโหลดวิดีโอ

ตัวอย่างข้อผิดพลาดเกี่ยวกับเว็บไซต์แชร์วิดีโอ

  • เว็บไซต์แชร์วิดีโอไม่สามารถจัดการชื่อไฟล์ที่มีช่องว่างได้ ต้องการชื่อ เช่น "My_Travels.mp4" หรือ "MyTravels.mp4" แทน "My Travels.mp4"
  • เว็บไซต์การแชร์วิดีโออัปโหลดวิดีโอที่มีขนาดใหญ่เกินขนาดไฟล์สูงสุดที่ยอมรับไม่ได้
  • เว็บไซต์การแชร์วิดีโอไม่รองรับตัวแปลงรหัสวิดีโอในวิดีโอที่อัปโหลด

ตัวอย่างเหล่านี้อาจเกิดขึ้นได้ในชีวิตจริง ซึ่งคุณอาจเคยเจอมาแล้ว! ลองเลือกตัวอย่างหนึ่งจากแต่ละหมวดหมู่ก่อนหน้านี้ และพูดคุยถึงประเด็นต่อไปนี้

  • ลักษณะการทำงานเริ่มต้นจะเป็นอย่างไรหากบริการแชร์วิดีโอจัดการกับตัวอย่างที่ระบุไม่ได้
  • ผู้ใช้คาดหวังว่าจะเกิดอะไรขึ้นในตัวอย่าง
  • เราจะปรับปรุงกระบวนการนี้ได้อย่างไร
การดำเนินการ ผู้ใช้เริ่มอัปโหลดไฟล์วิดีโอที่ไม่ถูกต้อง จากนั้นระหว่างการอัปโหลด ผู้ใช้ระบุไฟล์วิดีโอที่ถูกต้องสำหรับการอัปโหลด
สิ่งที่จะเกิดขึ้นโดยค่าเริ่มต้น ไฟล์ต้นฉบับจะอัปโหลดต่อไปในเบื้องหลังขณะที่ไฟล์ใหม่อัปโหลดในเวลาเดียวกัน
สิ่งที่ผู้ใช้คาดหวัง ผู้ใช้คาดว่าการอัปโหลดต้นฉบับจะหยุดลงเพื่อไม่ให้ใช้แบนด์วิดท์อินเทอร์เน็ตเพิ่มเติมโดยสูญเปล่า
สิ่งที่ปรับปรุงได้ JavaScript จะยกเลิกคำขอดึงข้อมูลสำหรับไฟล์ต้นฉบับก่อนที่ระบบจะเริ่มอัปโหลดไฟล์ใหม่
การดำเนินการ ผู้ใช้ขาดการเชื่อมต่ออินเทอร์เน็ตระหว่างอัปโหลดวิดีโอ
สิ่งที่จะเกิดขึ้นโดยค่าเริ่มต้น แถบความคืบหน้าในการอัปโหลดดูเหมือนจะค้างอยู่ที่ 50% ในที่สุด Fetch API ก็จะหมดเวลาและระบบจะทิ้งข้อมูลที่อัปโหลด เมื่อการเชื่อมต่ออินเทอร์เน็ตกลับมาทำงานอีกครั้ง ผู้ใช้จะต้องอัปโหลดไฟล์อีกครั้ง
สิ่งที่ผู้ใช้คาดหวัง ผู้ใช้คาดหวังว่าจะได้รับแจ้งเมื่ออัปโหลดไฟล์ไม่ได้ และคาดหวังว่าการอัปโหลดจะกลับมาทำงานต่อโดยอัตโนมัติที่ 50% เมื่อกลับมาออนไลน์อีกครั้ง
สิ่งที่ปรับปรุงได้ หน้าการอัปโหลดจะแจ้งให้ผู้ใช้ทราบถึงปัญหาการเชื่อมต่ออินเทอร์เน็ต และมั่นใจได้ว่าการอัปโหลดจะกลับมาทำงานอีกครั้งเมื่อการเชื่อมต่ออินเทอร์เน็ตกลับมาทำงานอีกครั้ง
การดำเนินการ เว็บไซต์แชร์วิดีโอไม่สามารถจัดการชื่อไฟล์ที่มีเว้นวรรค แทนที่จะใช้ชื่อ "My Travels.mp4" ให้ใช้ชื่ออย่าง "My_Travels.mp4" หรือ "MyTravels.mp4"
สิ่งที่จะเกิดขึ้นโดยค่าเริ่มต้น ผู้ใช้ต้องรอให้อัปโหลดเสร็จสมบูรณ์ เมื่ออัปโหลดไฟล์แล้วและแถบความคืบหน้าแสดงข้อความว่า "100%" แถบความคืบหน้าจะแสดงข้อความว่า "โปรดลองอีกครั้ง"
สิ่งที่ผู้ใช้คาดหวัง ผู้ใช้คาดหวังว่าจะได้รับแจ้งข้อจำกัดของชื่อไฟล์ก่อนที่การอัปโหลดจะเริ่มขึ้น หรืออย่างน้อยก็ภายในวินาทีแรกของการอัปโหลด
สิ่งที่ควรปรับปรุง บริการแชร์วิดีโอควรรองรับชื่อไฟล์ที่มีการเว้นวรรค ตัวเลือกอื่นๆ คือการแจ้งให้ผู้ใช้ทราบถึงข้อจำกัดของชื่อไฟล์ก่อนที่จะเริ่มการอัปโหลด หรือบริการแชร์วิดีโอควรปฏิเสธการอัปโหลดพร้อมแสดงข้อความแสดงข้อผิดพลาดโดยละเอียด

จัดการข้อผิดพลาดด้วย Fetch API

โปรดทราบว่าตัวอย่างโค้ดต่อไปนี้ใช้ await ระดับบนสุด (การรองรับเบราว์เซอร์) เนื่องจากฟีเจอร์นี้ช่วยให้โค้ดของคุณเรียบง่ายขึ้น

เมื่อ Fetch API แสดงข้อผิดพลาด

ตัวอย่างนี้ใช้คำสั่งtry/catch บล็อก เพื่อตรวจหาข้อผิดพลาดที่เกิดขึ้นภายในบล็อก try เช่น หาก Fetch API ดึงข้อมูลทรัพยากรที่ระบุไม่ได้ ระบบจะแสดงข้อผิดพลาด ภายในบล็อก catch เช่นนี้ โปรดดูแลให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่มีความหมาย หากมีไอคอนหมุนซึ่งเป็นอินเทอร์เฟซผู้ใช้ทั่วไปที่แสดงความคืบหน้าบางอย่างให้ผู้ใช้เห็น คุณสามารถดำเนินการต่อไปนี้ภายในการบล็อก catch ได้

  1. นําตัวหมุนออกจากหน้า
  2. แสดงข้อความที่เป็นประโยชน์ซึ่งอธิบายสิ่งที่ผิดพลาดและตัวเลือกที่ผู้ใช้ทำได้
  3. แสดงปุ่ม "ลองอีกครั้ง" แก่ผู้ใช้ตามตัวเลือกที่มี
  4. เบื้องหลัง ระบบจะส่งรายละเอียดของข้อผิดพลาดไปยังบริการติดตามข้อผิดพลาดหรือแบ็กเอนด์ การดำเนินการนี้จะบันทึกข้อผิดพลาดเพื่อให้สามารถวินิจฉัยในขั้นตอนต่อไป
try {
  const response = await fetch('https://website');
} catch (error) {
  // TypeError: Failed to fetch
  console.log('There was an error', error);
}

ในขั้นตอนต่อมา ขณะที่วินิจฉัยข้อผิดพลาดที่บันทึกไว้ คุณสามารถเขียนกรณีทดสอบเพื่อจับข้อผิดพลาดดังกล่าวก่อนที่ผู้ใช้จะรู้ตัวว่าเกิดข้อผิดพลาด การทดสอบอาจเป็นการทดสอบหน่วย การผสานรวม หรือการยอมรับ ทั้งนี้ขึ้นอยู่กับข้อผิดพลาด

เมื่อรหัสสถานะเครือข่ายแสดงข้อผิดพลาด

ตัวอย่างโค้ดนี้จะส่งคำขอไปยังบริการทดสอบ HTTP ที่ตอบสนองด้วยรหัสสถานะ HTTP 429 Too Many Requests เสมอ สิ่งที่น่าสนใจคือคำตอบไม่ได้ไปถึงบล็อก catch สถานะ 404 จะไม่แสดงข้อผิดพลาดของเครือข่าย แต่จะแก้ไขตามปกติได้

หากต้องการตรวจสอบว่ารหัสสถานะ HTTP สำเร็จหรือไม่ คุณสามารถใช้ตัวเลือกใดก็ได้ต่อไปนี้

  • ใช้พร็อพเพอร์ตี้ Response.ok เพื่อระบุว่ารหัสสถานะอยู่ในช่วง 200 ถึง 299 หรือไม่
  • ใช้พร็อพเพอร์ตี้ Response.status เพื่อระบุว่าการตอบกลับสําเร็จหรือไม่
  • ใช้ข้อมูลเมตาอื่นๆ เช่น Response.headers เพื่อประเมินว่าการตอบกลับสําเร็จหรือไม่
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}`)
}

แนวทางปฏิบัติแนะนำคือให้ทำงานร่วมกับคนในองค์กรและทีมเพื่อทำความเข้าใจรหัสสถานะการตอบกลับ HTTP ที่อาจเกิดขึ้น ในบางครั้ง นักพัฒนาซอฟต์แวร์แบ็กเอนด์ ฝ่ายปฏิบัติการของนักพัฒนา และวิศวกรบริการสามารถให้ข้อมูลเชิงลึกที่เฉพาะเจาะจงเกี่ยวกับกรณีปัญหาที่อาจเป็นไปได้ที่คุณไม่คาดคิด

เมื่อเกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบกลับของเครือข่าย

ตัวอย่างโค้ดนี้แสดงข้อผิดพลาดอีกประเภทหนึ่งที่อาจเกิดขึ้นเมื่อแยกวิเคราะห์ข้อมูลโค้ดตอบกลับ อินเทอร์เฟซ Response มีวิธีการที่สะดวกในการแยกวิเคราะห์ข้อมูลประเภทต่างๆ เช่น ข้อความหรือ JSON ในโค้ดต่อไปนี้ ระบบจะส่งคําขอเครือข่ายไปยังบริการทดสอบ HTTP ซึ่งจะแสดงสตริง HTML เป็นเนื้อหาการตอบกลับ อย่างไรก็ตาม ระบบพยายามแยกวิเคราะห์เนื้อหาการตอบกลับเป็น JSON ซึ่งทำให้เกิดข้อผิดพลาด

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

คุณต้องเตรียมโค้ดให้รองรับรูปแบบการตอบกลับที่หลากหลาย และตรวจสอบว่าการตอบกลับที่ไม่คาดคิดจะไม่ทำให้หน้าเว็บใช้งานไม่ได้สำหรับผู้ใช้

ลองพิจารณาสถานการณ์ต่อไปนี้ คุณมีทรัพยากรระยะไกลที่แสดงผลการตอบกลับ JSON ที่ถูกต้อง และระบบแยกวิเคราะห์ข้อมูลดังกล่าวด้วยเมธอด Response.json() เรียบร้อยแล้ว บริการอาจหยุดทำงาน เมื่อปิดแล้ว ระบบจะแสดง 500 Internal Server Error หากไม่ได้ใช้เทคนิคการจัดการข้อผิดพลาดที่เหมาะสมระหว่างการแยกวิเคราะห์ JSON หน้าเว็บอาจใช้งานไม่ได้สำหรับผู้ใช้เนื่องจากระบบจะแสดงข้อผิดพลาดที่ไม่ได้รับการจัดการ

กรณีที่ต้องยกเลิกคำขอเครือข่ายก่อนที่คำขอจะเสร็จสมบูรณ์

ตัวอย่างโค้ดนี้ใช้ AbortController เพื่อยกเลิกคำขอที่อยู่ระหว่างดำเนินการ คำขอที่อยู่ระหว่างดำเนินการคือคำขอเครือข่ายที่เริ่มดำเนินการแล้วแต่ยังไม่เสร็จสมบูรณ์

สถานการณ์ที่คุณอาจต้องยกเลิกคำขอที่อยู่ระหว่างดำเนินการอาจแตกต่างกันไป แต่ท้ายที่สุดแล้วขึ้นอยู่กับ Use Case และสภาพแวดล้อมของคุณ โค้ดต่อไปนี้แสดงวิธีส่ง AbortSignal ไปยัง Fetch API AbortSignal แนบอยู่กับ AbortController และ AbortController มีเมธอด abort() ซึ่งบ่งบอกให้เบราว์เซอร์ยกเลิกคําขอเครือข่าย

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

บทสรุป

สิ่งสำคัญอย่างหนึ่งในการจัดการข้อผิดพลาดคือการระบุส่วนต่างๆ ที่อาจทำให้เกิดข้อผิดพลาด ตรวจสอบว่าคุณมีทางเลือกสำรองที่เหมาะสมสำหรับผู้ใช้สำหรับแต่ละสถานการณ์ ถามตัวเองด้วยคำถามต่อไปนี้เกี่ยวกับคำขอดึงข้อมูล

  • จะเกิดอะไรขึ้นหากเซิร์ฟเวอร์เป้าหมายหยุดทำงาน
  • จะเกิดอะไรขึ้นหากการดึงข้อมูลได้รับการตอบกลับที่ไม่คาดคิด
  • จะเกิดอะไรขึ้นหากการเชื่อมต่ออินเทอร์เน็ตของผู้ใช้ไม่สำเร็จ

คุณยังร่างผังงานที่อธิบายฟังก์ชันการทำงานและอินเทอร์เฟซผู้ใช้สำหรับสถานการณ์ต่างๆ ได้ด้วย ทั้งนี้ขึ้นอยู่กับความซับซ้อนของหน้าเว็บ