PlusMagi's Blog By Pitt Phunsanit API,Frontend,JavaScript,technology,Web การจัดการ Error ใน Fetch API: ทำไม HTTP 404/500 ถึงไม่ Throw Error และวิธีเช็ค response.ok แท้จริง

การจัดการ Error ใน Fetch API: ทำไม HTTP 404/500 ถึงไม่ Throw Error และวิธีเช็ค response.ok แท้จริง

ในโลกของการพัฒนาเว็บสมัยใหม่ การดึงข้อมูลจาก API หรือการเรียกใช้ทรัพยากรภายนอกถือเป็นหัวใจสำคัญของแอปพลิเคชันเกือบทุกประเภท อย่างไรก็ตาม เมื่อเราทำงานกับ Asynchronous JavaScript และ Network Requests เรามักจะพบกับความเข้าใจผิดที่พบบ่อยอย่างหนึ่ง นั่นคือการคิดว่าข้อผิดพลาดทาง HTTP ทุกรูปแบบ เช่น 404 Not Found หรือ 500 Internal Server Error จะถูกจัดการโดย Promise Rejection โดยอัตโนมัติ ซึ่งหากไม่ระวัง อาจทำให้โค้ดของเราทำงานต่อด้วยข้อมูลที่ไม่ถูกต้องหรือเกิด Bug ที่ยากต่อการแก้ไข


เจาะลึกรายละเอียดและประเด็นสำคัญ

ในเชิงเทคนิคแล้ว, Fetch API ถูกออกแบบมาให้ Promise Reject เฉพาะเมื่อเกิด “Network Failure” เท่านั้น (เช่น ไม่มีอินเทอร์เน็ต หรือ CORS Policy ล้มเหลว) แต่จะไม่ Throw Error เมื่อเซิร์ฟเวอร์ตอบกลับด้วยสถานะโค้ดที่บ่งชี้ถึงความล้มเหลวทางตรรกะของแอปพลิเคชัน (Logical Errors) เช่น 4xx หรือ 5xx ดังนั้น การที่เราได้รับ Response Object กลับมาอย่างสมบูรณ์ แม้ว่าเนื้อหาจะผิดพลาด ก็ไม่ได้หมายความว่าการเรียก API นั้นสำเร็จเสมอไป

กุญแจสำคัญในการแก้ไขปัญหานี้คือการตรวจสอบคุณสมบัติที่ชื่อว่า response.ok ซึ่งเป็น Boolean Property ที่ Fetch API เพิ่มเข้ามาให้โดยเฉพาะ คุณจะต้องเรียกใช้ fetch() และทำการตรวจสอบสถานะโค้ด (Status Code) ด้วยตัวเองเสมอ หาก response.ok เป็น false นั่นหมายความว่า HTTP Status Code อยู่ในช่วง 400 ถึง 599 ซึ่งเป็นสัญญาณที่บ่งบอกถึงข้อผิดพลาดทาง API ที่เราต้องจัดการด้วยการโยน Error ออกมาเอง

async function fetchData(url) {
  try {
    const response = await fetch(url);

    // 💡 ขั้นตอนสำคัญ: ตรวจสอบสถานะ HTTP Code ด้วย response.ok
    if (!response.ok) {
      // สร้าง Error ใหม่เพื่อจับใน catch block และระบุสถานะโค้ดที่ชัดเจน
      throw new Error(`HTTP error! Status: ${response.status} (${response.statusText})`);
    }

    const data = await response.json();
    return data;

  } catch (error) {
    // ส่วนนี้จะจับ Network Errors หรือ Error ที่เราโยนออกมาจาก if (!response.ok)
    console.error("Failed to fetch data:", error.message);
    throw error; // โยน Error ต่อไปเพื่อให้ส่วนที่เรียกใช้จัดการได้
  }
}

// ตัวอย่างการใช้งาน:
fetchData('https://api.example.com/nonexistent-endpoint')
  .then(data => console.log("Success:", data))
  .catch(error => console.warn("Handling Error on Client Side:", error.message));


การนำไปประยุกต์ใช้ในชีวิตและการทำงานยุคใหม่

  • การสร้าง User Experience ที่แข็งแกร่ง (UX): แทนที่จะแสดงข้อความ Error ทั่วไปอย่าง “Failed to load data” เราควรใช้ Status Code ที่เราจับได้ (เช่น 401 Unauthorized หรือ 403 Forbidden) เพื่อแจ้งให้ผู้ใช้งานทราบว่าพวกเขาต้องดำเนินการอะไรต่อไป เช่น “โปรดเข้าสู่ระบบใหม่” หรือ “บัญชีของคุณถูกระงับชั่วคราว”
  • การออกแบบ Retry Mechanism และ Circuit Breaker: ในระดับ Enterprise Application เราไม่ควรล้มเหลวทันทีเมื่อเกิด 5xx Error ควรมีการใช้กลไกการลองใหม่ (Retry) โดยมี Backoff Strategy หรือหากพบข้อผิดพลาดซ้ำๆ ติดต่อกันหลายครั้ง ควรเปิดใช้งาน Circuit Breaker เพื่อหยุดเรียก API ชั่วคราว ป้องกันการโหลดเซิร์ฟเวอร์มากเกินไป

การจัดการ Error ใน Fetch API ไม่ใช่แค่การเขียนโค้ดให้ทำงานได้ แต่คือการสร้างความทนทาน (Resilience) ให้กับแอปพลิเคชันของเรา การเข้าใจว่า Promise Rejection กับ HTTP Status Code คือคนละเรื่องกัน จะช่วยยกระดับคุณภาพของโค้ดจากระดับที่ “ใช้งานได้” ไปสู่ระดับที่ “เชื่อถือได้” อย่างแท้จริง


อ่านเพิ่มเติม