Now.js Framework Documentation
AuthErrorHandler - การจัดการข้อผิดพลาดสำหรับการตรวจสอบสิทธิ์
AuthErrorHandler - การจัดการข้อผิดพลาดสำหรับการตรวจสอบสิทธิ์
เอกสารฉบับนี้อธิบาย AuthErrorHandler ซึ่งเป็นระบบจัดการข้อผิดพลาดสำหรับกระบวนการตรวจสอบสิทธิ์ของ Now.js Framework
📋 สารบัญ
ภาพรวม
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 objectcontext(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
}เอกสารที่เกี่ยวข้อง
- Authentication.md - Authentication system overview
- AuthManager.md - Core authentication manager
- AuthGuard.md - Route protection
- TokenService.md - JWT token management
- AuthLoadingManager.md - Loading states