[미들웨어]글로벌 에러 핸들러 - gyunam-bark/nb02-how-do-i-look-team1 GitHub Wiki
글로벌 에러핸들러 미들웨어 설계
설계 개요
-
DEV(개발), SERVICE(사용자)에 따른 반환 객체 구분
-
가능한 많은 statusCode 적용
-
비표준 statusCode 가 들어올 경우 500 으로 예외처리
적용 예시
import errorHandler from 'error-middleware.js';
// ...app.use(routes)
app.use(errorHandler);
지원 상태 코드
MDN 참고
상태 코드 | 메세지 |
---|---|
100 | Continue |
101 | Switching Protocols |
102 | Processing |
300 | Multiple Chocies |
301 | Moved Permanently |
302 | Found |
303 | See Other |
304 | Not Modified |
307 | Temporary Redirect |
308 | Permanent Redirect |
400 | Bad Request |
401 | Unauthorized |
403 | Forbidden |
405 | Method Not Allowed |
409 | Conflict |
410 | Gone |
415 | Unsupported Media Type |
422 | Unprocessable Entity |
429 | Too Many Requests |
500 | Internal Server Error |
501 | Not Implemented |
502 | Bad Gateway |
503 | Service Unavailable |
504 | Gateway Timeout |
치명적인 서버 에러가 발생했을 때 에러 핸들러
(TODO)
- index.js, server.js, app.js 등의 진입점 파일 최상단에 위치
- Node.js 프로세스 레벨의 글로벌 에러 핸들러
- uncaughtException: try-catch로 잡히지 않은 동기 에러
process.on('uncaughtException', err => {
console.error('--- UNCAUGHT EXCEPTION! 서버가 강제 종료됩니다 ---');
console.error('에러 종류:', err.name);
console.error('에러 메시지:', err.message);
console.error('발생 위치 (스택):', err.stack);
// 실제 서비스에서는 로깅 시스템 (e.g., Winston, Pino)에 기록 후 알림
process.exit(1); // 프로세스 즉시 종료
});
치명적인 서버 에러 테스트 코드
(TODO)
// uncaughtException 발생 테스트 코드 (동기 코드 오류)
// 1. 정의되지 않은 변수 참조 (ReferenceError)
function triggerReferenceError() {
console.log(nonExistentVariable); // 'nonExistentVariable'은 정의되지 않음
}
// 2. null 또는 undefined 값의 속성에 접근 (TypeError)
function triggerTypeError() {
const obj = null;
console.log(obj.property); // null의 속성에 접근 시도
}
// 3. 존재하지 않는 함수 호출 (TypeError)
function triggerFunctionError() {
nonExistentFunction(); // 정의되지 않은 함수 호출
}
// --- 테스트를 위한 호출 ---
// 아래 함수 중 하나만 주석을 해제하고 실행하여 테스트하세요.
// triggerReferenceError();
// triggerTypeError();
// triggerFunctionError();
// 이 라인은 위의 에러가 발생하면 실행되지 않습니다.
console.log('App is running smoothly (if no error occurred).');
// Express 앱과 함께 테스트하는 경우:
// const express = require('express');
// const app = express();
//
// app.get('/trigger-uncaught-error', (req, res) => {
// console.log(thisVariableDoesNotExist); // 요청 처리 중 동기 에러 발생
// res.send('You should not see this response.');
// });
//
// const port = 3000;
// app.listen(port, () => {
// console.log(`Server running on port ${port}`);
// });
//unhandledRejection 발생 테스트 코드 (비동기 Promise 오류)
// 1. .catch() 핸들러가 없는 Promise 거부
function triggerUnhandledPromiseRejection() {
new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('네트워크 연결 실패!')); // Promise 거부
}, 100); // 100ms 후 발생
});
}
// 2. async/await 함수 내에서 try-catch가 없는 Promise 거부
async function triggerAsyncError() {
await new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('비동기 작업 중 치명적인 오류 발생!'));
}, 200); // 200ms 후 발생
});
console.log('This line will not be reached.'); // 에러 발생 시 이 줄은 실행되지 않음
}
// --- 테스트를 위한 호출 ---
// 아래 함수 중 하나만 주석을 해제하고 실행하여 테스트하세요.
// triggerUnhandledPromiseRejection();
// triggerAsyncError();
console.log('App is running (waiting for promise rejection).');
// Express 앱과 함께 테스트하는 경우:
// const express = require('express');
// const app = express();
//
// app.get('/trigger-unhandled-rejection', async (req, res) => {
// await Promise.reject(new Error('이 Promise는 처리되지 않습니다.'));
// res.send('You should not see this response.');
// });
//
// const port = 3000;
// const server = app.listen(port, () => {
// console.log(`Server running on port ${port}`);
// });
//
// process.on('unhandledRejection', (err, promise) => {
// console.error('--- 🚨 UNHANDLED REJECTION CAUGHT IN EXPRESS! 🚨 ---');
// console.error(err);
// server.close(() => { // 서버를 우아하게 종료
// process.exit(1);
// });
// });
치명적인 서버 에러가 발생했을 때 에러 (종료 확인):
(TODO)
- 브라우저에서 http://localhost:3000/test-crash 로 접속합니다. 터미널에 UNCAUGHT EXCEPTION! 로그가 출력되고 서버가 종료되는 것을 확인합니다.
- 브라우저에서 http://localhost:3000/test-promise-rejection 로 접속합니다. 터미널에 UNHANDLED REJECTION! 로그가 출력되고 서버가 종료되는 것을 확인합니다.
테스트 코드
// 테스트용 에러 유도 라우트
app.get('/error', (req, res, next) => {
const error = new Error();
// 이 에러 코드 숫자만 바꿔가면서 하면 됩니다.
error.statusCode = 400;
next(error);
});
// 글로벌 에러 핸들러
app.use(errorHandler);
미들웨어 코드