
먼저, 가장 기본적인 에러 핸들링 미들웨어를 살펴보자. 이 미들웨어는 모든 종류의 에러를 잡아내고, 사용자에게 500 상태 코드와 함께 간단한 메시지를 보낸다.
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something went wrong!');
});
특정 유형의 에러에 대해 다르게 반응하도록 미들웨어를 설정할 수 있다. 예를 들어, 애플리케이션에서 발생할 수 있는 'NotFound' 에러에 대해 다음과 같이 처리할 수 있다.
class NotFoundError extends Error {
constructor(message) {
super(message);
this.name = "NotFoundError";
this.status = 404;
}
}
app.use((err, req, res, next) => {
if (err instanceof NotFoundError) {
return res.status(404).sendFile('/path/to/404.html');
}
next(err);
});
Express에서 비동기 코드에서 발생하는 에러를 처리하기 위해서는 next 함수를 사용해야 한다. 비동기 함수 내에서 발생한 에러를 next로 전달하면, Express는 이를 적절한 에러 핸들링 미들웨어로 이동시킨다.
app.get('/some-async-route', async (req, res, next) => {
try {
let data = await someAsyncOperation();
res.send(data);
} catch (err) {
next(err); // 비동기 에러를 핸들링 미들웨어로 전달
}
});
앞서 언급한 것처럼, 에러가 발생했을 때 사용자에게 HTML 페이지를 보여주는 것은 좋은 방법이다. 이를 위해 res.sendFile 메서드를 사용하여 특정 경로의 HTML 파일을 사용자에게 보낼 수 있다.
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).sendFile('/path/to/error-page.html');
});
실제 프로덕션 환경에서는 에러를 로깅하고 모니터링하는 것이 중요하다. 이를 위해 console.error, 파일 로깅, 혹은 외부 모니터링 서비스를 사용할 수 있다.
app.use((err, req, res, next) => {
console.error(err.stack); // 콘솔에 에러 로깅
// 추가적으로 파일 로깅이나 모니터링 서비스를 사용할 수 있음
res.status(500).send('Something went wrong!');
});
에러 핸들링 로직을 모듈화하고, 다양한 유형의 에러에 대해 확장 가능하고 유지보수하기 쉬운 구조를 만드는 것이 중요하다. 이를 위해 에러 클래스를 정의하고, 각 클래스별로 다른 처리 방법을 구현할 수 있다.
Express에서의 에러 핸들링은 애플리케이션의 안정성과 사용자 경험을 크게 향상시킬 수 있다. (실제로, 대부분의 서비스를 보면 오류가 날 시 특정 오류 페이지로 이동시켜준다) 기본적인 에러 핸들링에서 시작하여, 애플리케이션의 요구사항에 맞게 점차 확장하고 세분화하는 것이 좋다.
실제 현업에서도 이러한 원칙을 따르면서도, 더 많은 자동화, 세분화된 모니터링 시스템, 그리고 사용자 친화적인 에러 페이지를 제공함으로써 에러 핸들링 기법을 사용한다고 한다.