Now.js Framework Documentation

Now.js Framework Documentation

AuthErrorHandler - การจัดการข้อผิดพลาดสำหรับการตรวจสอบสิทธิ์

TH 04 Sep 2026 01:40

AuthErrorHandler - การจัดการข้อผิดพลาดสำหรับการตรวจสอบสิทธิ์

เอกสารฉบับนี้อธิบาย AuthErrorHandler ซึ่งเป็นระบบจัดการข้อผิดพลาดสำหรับกระบวนการตรวจสอบสิทธิ์ของ Now.js Framework

📋 สารบัญ

  1. ภาพรวม
  2. การติดตั้งและนำเข้า
  3. การเริ่มต้นใช้งาน

ภาพรวม

AuthErrorHandler จัดการข้อผิดพลาด และข้อยกเว้น ที่เกิดขึ้นในกระบวนการตรวจสอบสิทธิ์ พร้อมส่งต่อการตอบสนองและกระบวนการกู้คืนอย่างเหมาะสม

ฟีเจอร์หลัก

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

เมื่อไหร่ควรใช้ AuthErrorHandler

✅ ใช้ AuthErrorHandler เมื่อ:

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

❌ ไม่ควรใช้เมื่อ:

  • ต้องการจัดการข้อผิดพลาดด้วยโค้ดแบบแมนนวลทั้งหมด
  • แอปพลิเคชันไม่ได้ใช้ระบบตรวจสอบสิทธิ์ของ Now.js

การติดตั้งและนำเข้า

AuthErrorHandler โหลดมาพร้อมกับ Now.js Framework และพร้อมใช้งานทันทีผ่าน window object:

// ไม่ต้อง import - พร้อมใช้งานทันที
console.log(window.AuthErrorHandler); // อ็อบเจ็กต์ AuthErrorHandler ที่ผูกไว้กับ window

การเริ่มต้นใช้งาน

การตั้งค่าพื้นฐาน

// AuthErrorHandler ทำงานร่วมกับ AuthManager โดยอัตโนมัติ
// ไม่จำเป็นต้องมีขั้นตอนเริ่มต้นแยกต่างหาก

await AuthManager.init({
  enabled: true,
  endpoints: {
    login: '/api/auth/login',
    verify: '/api/auth/verify'
  },

  // การกำหนดค่าการจัดการข้อผิดพลาด
  errorHandling: {
    // จำนวนครั้งสูงสุดในการลองใหม่
    maxRetries: 3,

    // ระยะเวลาหน่วงก่อนลองใหม่ (มิลลิวินาที)
    retryDelay: 1000,

    // แสดงการแจ้งเตือนให้ผู้ใช้
    showNotifications: true,

    // บันทึกข้อผิดพลาดลงคอนโซล
    logErrors: true
  }
});

console.log('AuthErrorHandler เริ่มทำงานร่วมกับ AuthManager แล้ว');

Error Handling Flow

การดำเนินการล้มเหลว
     ↓
┌────────────────────┐
│  จำแนกข้อผิดพลาด │
│  - เครือข่ายหรือไม่?  │
│  - การตรวจสอบสิทธิ์หรือไม่? │
│  - การอนุญาตหรือไม่? │
│  - การตรวจสอบข้อมูลหรือไม่? │
└──────┬─────────────┘
       ↓
┌────────────────────┐
│ เลือกการดำเนินการ │
│  - ลองใหม่หรือไม่? │
│  - เปลี่ยนเส้นทางหรือไม่? │
│  - แจ้งเตือนหรือไม่? │
│  - บันทึกหรือไม่? │
└──────┬─────────────┘
       ↓
┌────────────────────┐
│ ปฏิบัติตามแผนที่เลือก │
│  - ลองทำงานซ้ำ      │
│  - เปลี่ยนเส้นทาง   │
│  - แสดงข้อความ      │
│  - บันทึกข้อผิดพลาด │
└──────┬─────────────┘
       ↓
┌────────────────────┐
│ ส่งเหตุการณ์ข้อผิดพลาด │
│  - เรียกตัวจัดการแบบกำหนดเอง │
│  - บันทึกเพื่อติดตาม │
│  - เก็บ log เพิ่มเติม │
└────────────────────┘

ประเภท Error

AuthErrorHandler รองรับ error types หลักๆ:

1. NETWORK_ERROR

การเชื่อมต่อเครือข่ายล้มเหลว

// เกิดขึ้นเมื่อ:
// - ไม่มีการเชื่อมต่ออินเทอร์เน็ต
// - ไม่สามารถเข้าถึงเซิร์ฟเวอร์ได้
// - คำขอหมดเวลา
// - ถูกปฏิเสธโดยนโยบาย CORS

// การดำเนินการเริ่มต้น: ลองใหม่ด้วยการหน่วงแบบยกกำลัง
{
  type: 'NETWORK_ERROR',
  message: 'Network connection failed',
  retryable: true,
  action: 'retry'
}

2. UNAUTHORIZED

ยังไม่ได้รับการตรวจสอบสิทธิ์หรือโทเค็นหมดอายุ

// เกิดขึ้นเมื่อ:
// - ไม่มีโทเค็นสำหรับพิสูจน์ตัวตน
// - โทเค็นหมดอายุ
// - โทเค็นไม่ถูกต้อง
// - โทเค็นถูกเพิกถอน

// การดำเนินการเริ่มต้น: เปลี่ยนเส้นทางไปหน้าลงชื่อเข้าใช้
{
  type: 'UNAUTHORIZED',
  message: 'Authentication required',
  retryable: false,
  action: 'redirect',
  target: '/login'
}

3. FORBIDDEN

ตรวจสอบสิทธิ์แล้วแต่ไม่มีสิทธิ์เข้าถึง

// เกิดขึ้นเมื่อ:
// - ไม่มีบทบาทที่ต้องการ
// - ไม่มีสิทธิ์ที่กำหนดไว้
// - การเข้าถึงถูกปฏิเสธโดยนโยบายความปลอดภัย

// การดำเนินการเริ่มต้น: แสดงหน้าแจ้งข้อผิดพลาด
{
  type: 'FORBIDDEN',
  message: 'Access denied',
  retryable: false,
  action: 'render',
  target: '/403'
}

4. VALIDATION_ERROR

ข้อมูลไม่ผ่านการตรวจสอบความถูกต้อง

// เกิดขึ้นเมื่อ:
// - ข้อมูลประจำตัวไม่ถูกต้อง
// - ขาดฟิลด์ที่จำเป็น
// - รูปแบบข้อมูลไม่ตรงตามที่กำหนด

// การดำเนินการเริ่มต้น: แสดงรายละเอียดข้อผิดพลาดให้ผู้ใช้ทราบ
{
  type: 'VALIDATION_ERROR',
  message: 'Invalid input',
  errors: {
    email: 'Invalid email format',
    password: 'Password too short'
  },
  retryable: true,
  action: 'notify'
}

5. TOKEN_EXPIRED

โทเค็นหมดอายุ

// เกิดขึ้นเมื่อ:
// - โทเค็นสำหรับเข้าถึง หมดอายุ
// - โทเค็นสำหรับรีเฟรช หมดอายุ

// การดำเนินการเริ่มต้น: พยายามรีเฟรชโทเค็น แล้วค่อยเปลี่ยนเส้นทางถ้าจำเป็น
{
  type: 'TOKEN_EXPIRED',
  message: 'Token expired',
  retryable: true,
  action: 'refresh',
  fallback: 'redirect',
  target: '/login'
}

6. TOKEN_REFRESH_FAILED

การรีเฟรชโทเค็นล้มเหลว

// เกิดขึ้นเมื่อ:
// - โทเค็นสำหรับรีเฟรชไม่ถูกต้อง
// - ปลายทางสำหรับรีเฟรชตอบกลับข้อผิดพลาด
// - ไม่มีโทเค็นสำหรับรีเฟรช

// การดำเนินการเริ่มต้น: เปลี่ยนเส้นทางไปหน้าลงชื่อเข้าใช้ใหม่
{
  type: 'TOKEN_REFRESH_FAILED',
  message: 'Failed to refresh token',
  retryable: false,
  action: 'redirect',
  target: '/login'
}

7. SESSION_EXPIRED

เซสชันหมดอายุ

// เกิดขึ้นเมื่อ:
// - เซสชันหมดเวลา
// - เซสชันถูกยกเลิกด้วยเหตุผลด้านความปลอดภัย
// - มีการออกจากระบบจากอุปกรณ์อื่น

// การดำเนินการเริ่มต้น: เปลี่ยนเส้นทางไปหน้าลงชื่อเข้าใช้ พร้อมแจ้งผู้ใช้
{
  type: 'SESSION_EXPIRED',
  message: 'Your session has expired',
  retryable: false,
  action: 'redirect',
  target: '/login',
  notify: true
}

8. RATE_LIMIT_EXCEEDED

ส่งคำขอเกินขีดจำกัด

// เกิดขึ้นเมื่อ:
// - มีคำขอต่อเนื่องมากเกินไป
// - เกินขีดจำกัดที่เซิร์ฟเวอร์ตั้งไว้

// การดำเนินการเริ่มต้น: หน่วงเวลาตามที่ระบบแนะนำก่อนลองใหม่อีกครั้ง
{
  type: 'RATE_LIMIT_EXCEEDED',
  message: 'Too many requests',
  retryable: true,
  action: 'retry',
  retryAfter: 60000,  // 1 นาที
  notify: true
}

9. SERVER_ERROR

ข้อผิดพลาดภายในเซิร์ฟเวอร์

// เกิดขึ้นเมื่อ:
// - เซิร์ฟเวอร์ส่งสถานะ 500
// - มีข้อยกเว้นเกิดขึ้นในฝั่งเซิร์ฟเวอร์
// - ระบบฐานข้อมูลตอบสนองผิดพลาด

// การดำเนินการเริ่มต้น: ลองใหม่จำนวนจำกัดพร้อมการหน่วงเวลา
{
  type: 'SERVER_ERROR',
  message: 'Server error occurred',
  retryable: true,
  action: 'retry',
  maxRetries: 3
}

10. CSRF_ERROR

โทเค็น CSRF ไม่ถูกต้อง

// เกิดขึ้นเมื่อ:
// - ไม่มีโทเค็น CSRF แนบมากับคำขอ
// - โทเค็น CSRF ไม่ตรงกับที่ระบบคาดหวัง
// - โทเค็น CSRF หมดอายุ

// การดำเนินการเริ่มต้น: รีเฟรชโทเค็น CSRF แล้วลองทำงานใหม่อีกครั้ง
{
  type: 'CSRF_ERROR',
  message: 'CSRF validation failed',
  retryable: true,
  action: 'refresh_csrf',
  fallback: 'reload'
}

11. CUSTOM_ERROR

ข้อผิดพลาดที่นิยามเอง

// เกิดจากตรรกะของแอปพลิเคชันที่กำหนดขึ้นมาเอง
{
  type: 'CUSTOM_ERROR',
  code: 'SUBSCRIPTION_REQUIRED',
  message: 'ต้องมีการสมัครสมาชิกที่ยังใช้งานอยู่',
  retryable: false,
  action: 'custom',
  handler: 'handleSubscriptionError'
}

การดำเนินการ Error

1. การลองใหม่

// ลองทำงานที่ล้มเหลวอีกครั้งโดยอัตโนมัติ
{
  action: 'retry',
  maxRetries: 3,
  retryDelay: 1000,
  backoff: 'exponential'  // linear (เส้นตรง), exponential (ยกกำลัง), fixed (คงที่)
}

// ลองใหม่ด้วยการหน่วงแบบยกกำลัง
// ครั้งที่ 1: หน่วง 1 วินาที
// ครั้งที่ 2: หน่วง 2 วินาที
// ครั้งที่ 3: หน่วง 4 วินาที

2. การเปลี่ยนเส้นทาง

// เปลี่ยนเส้นทางไปยัง route อื่น
{
  action: 'redirect',
  target: '/login',
  reason: 'Authentication required',
  storeIntendedRoute: true  // เก็บเส้นทางปัจจุบันไว้ชั่วคราว
}

// หลังจากลงชื่อเข้าใช้ เปลี่ยนเส้นทางกลับไปยังหน้าที่ต้องการ

3. การแสดงผล

// แสดงหน้าข้อผิดพลาด
{
  action: 'render',
  target: '/403',
  context: {
    error: 'Access denied',
    requiredRole: 'admin'
  }
}

4. การแจ้งเตือน

// แสดงการแจ้งเตือนให้ผู้ใช้
{
  action: 'notify',
  notification: {
    type: 'error',
    title: 'Login Failed',
    message: 'Invalid credentials',
    duration: 5000
  }
}

5. การบล็อก

// บล็อกการนำทาง อยู่ในหน้าปัจจุบัน
{
  action: 'block',
  reason: 'Unsaved changes',
  confirm: true  // แสดงกล่องยืนยันก่อนดำเนินการต่อ
}

6. การรีเฟรช

// รีเฟรชโทเค็นชุดปัจจุบัน
{
  action: 'refresh',
  type: 'token',
  fallback: {
    action: 'redirect',
    target: '/login'
  }
}

7. การออกจากระบบ

// บังคับออกจากระบบ
{
  action: 'logout',
  reason: 'Session invalidated',
  redirect: '/login',
  notify: true
}

8. การดำเนินการแบบกำหนดเอง

// ดำเนินการ handler แบบกำหนดเอง
{
  action: 'custom',
  handler: async (error, context) => {
    console.log('Custom error handler:', error);

    // ตรรกะแบบกำหนดเอง
    if (error.code === 'PAYMENT_REQUIRED') {
      await showPaymentModal();
    }

    return { handled: true };
  }
}

เหตุการณ์ Error

AuthErrorHandler ส่งเหตุการณ์เดียวผ่าน EventManager โดยระบุชนิดของข้อผิดพลาด
ไว้ใน payload ไม่ได้แยกเป็นคนละ event ต่อชนิด

Event เมื่อเกิด Detail
auth:error จัดการข้อผิดพลาดด้าน auth หนึ่งครั้ง {errorInfo, config, context, timestamp}
EventManager.on('auth:error', ({errorInfo, context}) => {
  // แยกชนิดจาก errorInfo แทนการฟังหลาย event
  switch (errorInfo.type) {
    case 'unauthorized':
      console.log('User unauthorized');
      break;
    case 'network':
      showOfflineIndicator();
      break;
    default:
      console.log('Auth error:', errorInfo.type, context);
  }
});

เอกสารอ้างอิง API

เมธอด

handleError(error, context)

จัดการ error ด้วย actions ที่กำหนดไว้

พารามิเตอร์:

  • error (Object/Error) - Error object
  • context (Object) - Error context

คืนค่า: Promise<Object> - ผลลัพธ์การจัดการ

ตัวอย่าง:

try {
  await AuthManager.login(credentials);
} catch (error) {
  await AuthErrorHandler.handleError(error, {
    operation: 'login',
    route: Router.getCurrentRoute()
  });
}

แนวทางปฏิบัติที่ดี

1. จัดการข้อผิดพลาดอย่างสง่างาม

// ✅ ดี - จัดการข้อผิดพลาดอย่างสง่างาม
try {
  await AuthManager.login(credentials);
} catch (error) {
  // ข้อผิดพลาดถูกจัดการโดย AuthErrorHandler โดยอัตโนมัติ
  console.log('Login failed, error handled');
}

// ❌ ไม่ดี - ไม่มีการจัดการข้อผิดพลาด
await AuthManager.login(credentials);  // ข้อผิดพลาดไม่ถูกจัดการ!

2. ให้ข้อมูลย้อนกลับแก่ผู้ใช้

// ✅ ดี - ให้ข้อมูลย้อนกลับที่ชัดเจนแก่ผู้ใช้
EventManager.on('auth:error', ({errorInfo}) => {
  if (errorInfo.type !== 'validation') return;
  showValidationErrors(errorInfo.errors);
  showNotification('Please fix the errors and try again', 'error');
});

// ❌ ไม่ดี - ล้มเหลวแบบเงียบๆ
// ผู้ใช้ไม่รู้ว่าเกิดอะไรขึ้น

3. บันทึกข้อผิดพลาดอย่างเหมาะสม

// ✅ ดี - บันทึกข้อผิดพลาดแบบมีโครงสร้าง
EventManager.on('auth:error', (e) => {
  const { error, context } = e.detail;

  logger.error({
    type: error.type,
    message: error.message,
    context: context,
    timestamp: new Date().toISOString()
  });
});

// ❌ ไม่ดี - ไม่มีการบันทึก
// ไม่สามารถ debug ปัญหาใน production ได้

4. ใช้การลองใหม่ที่มีขีดจำกัด

// ✅ ดี - ลองใหม่ด้วยการหน่วงแบบยกกำลัง และมีขีดจำกัด
{
  maxRetries: 3,
  retryBackoff: 'exponential',
  retryDelay: 1000
}

// ❌ ไม่ดี - ลองใหม่ไม่จำกัดจำนวนครั้ง
{
  maxRetries: Infinity  // ไม่มีวันหยุดพยายาม!
}

ข้อผิดพลาดที่พบบ่อย

1. ไม่จัดการข้อผิดพลาดทุกประเภท

// ❌ ไม่ดี - จัดการเฉพาะกรณีไม่ได้รับอนุญาต
EventManager.on('auth:error', ({errorInfo}) => {
  if (errorInfo.type === 'unauthorized') redirectToLogin();
});
// แล้วข้อผิดพลาดด้านเครือข่ายล่ะ? แล้วข้อผิดพลาดจากการตรวจสอบข้อมูลล่ะ?

// ✅ ดี - จัดการข้อผิดพลาดทุกประเภท
EventManager.on('auth:error', (e) => {
  const { error } = e.detail;

  switch (error.type) {
    case 'UNAUTHORIZED':
      redirectToLogin();
      break;
    case 'NETWORK_ERROR':
      showOfflineMode();
      break;
    case 'VALIDATION_ERROR':
      showValidationErrors(error.errors);
      break;
    default:
      showGenericError(error.message);
  }
});

2. กลืนข้อผิดพลาด

// ❌ ไม่ดี - ข้อผิดพลาดหายไป
try {
  await AuthManager.login(credentials);
} catch (error) {
  // ไม่ทำอะไร - ข้อผิดพลาดสูญหาย
}

// ✅ ดี - อย่างน้อยก็บันทึกข้อผิดพลาด
try {
  await AuthManager.login(credentials);
} catch (error) {
  console.error('Login failed:', error);
  // ส่งต่อให้ AuthErrorHandler จัดการต่อ
  throw error;
}

3. ลองใหม่โดยไม่มี Backoff

// ❌ ไม่ดี - ลองใหม่ทันทีตลอดเวลา
{
  retryBackoff: 'fixed',
  retryDelay: 0,
  maxRetries: 999
}
// นี่มันทำลายเซิร์ฟเวอร์ชัดๆ!

// ✅ ดี - ใช้การหน่วงแบบยกกำลัง ที่มีขีดจำกัด
{
  retryBackoff: 'exponential',
  retryDelay: 1000,
  maxRetries: 3
}

เอกสารที่เกี่ยวข้อง