나의개발일지
[Express] 알아보자!! Error-handler 사용하자!! Error-handler 포기하자..... 본문
[Express] 알아보자!! Error-handler 사용하자!! Error-handler 포기하자.....
kdy9kdy 2023. 1. 20. 23:19
본 글은 작성자가 어디선가 주워듣고 이해한 내용들을 개인적인 언어로 작성한 게시물입니다.
잘못된 내용이 존재할 수 있으니, 읽게 되신다면 이점을 감안해 주세요!!!
- 우리는 결국 자신이 가진 이야기로 상대방을 이해할 수 있을 뿐이다.-
이번 주제는 error핸들러... 강의를 보면서 익숙해지고 이해하려고 하는데 좀처럼 생각대로 되지 않는다. 왜지????라는 의문을 가지고서 이해한 내용을 작성한다. 이번 글은 다른 포스팅글에 비해서 잘못된 내용이 많이 포함될 거 같은 느낌적인 느낌이 드는 것은 착각이기를 바라면서 에러핸들러를 알아보자!!!!
에러 핸들러????
에러핸들러가 뭘까??라는 간단한 개념부터 집고 넘어가자니 내가 아는 에러핸들러는 코드가 실행 중에 비정상적인 종료가 되지 않도록(?) 에러가 발생할 수 있는 곳에 코드를 집어넣어서 내가 원하는 결과를 만드는 것이 에러 핸들러라고 생각한다. 예를 들어 상품의 id값을 path파라미터에 받아서 데이터를 찾는 경우라고 가정해 보자!! 만약 에러핸들러가 없다면, 누군가 잘못해서 id값을 잘못 입력하게 되면 웹사이트는 멈추게 된다. id에 해당하는 값이 없기 때문이다. 그런데, id값이 없는 것에 대한 에러 핸들러를 하게 되면, 비정상적인 종료가 발생하지 않게 된다. 그리고 이용자에게도 메시지를 보낼 수 있다. "해당 id에 속하는 상품은 존재하지 않습니다."와 같은 메시지를 보낼 수 있다. 그러니까 에러 핸들러의 궁극적인 목표는 사용자에게 편의를 주면서 비정상적인 종료가 되지 않도록 하는 것이라고 생각한다. 그런데 문제는 모든 에러에 대해서 우리가 알 수 없다는 것이다. 100명의 사람이 있다면 100의 생각은 모두 다르기 때문에 우리가 모든 사람이 어떻게 행동하는지에 대해서 예측할 수 없다. 하지만 보편적으로 나타나는 에러에 대해서는 알 수 있고, 이러한 에러들을 핸들링하는 방법에 초점을 맞추어야 할 것이다. 모든 에로를 핸들링한다는 것은 불가능한 일 일 것이다.
express 에러 핸들러
express는 기본적으로 미들웨어나 라우트 콜백, 라우트 핸들러에서 발생하는 오류에 대해서 잡아내서 디폴트 에러 핸들러를 이용해서 처리를 한다. 우리는 디폴트 에러 핸들러가 아닌 직접 에러 핸들러를 작성하려고 하는 것이다. 커스텀 에러 핸들러를 만드는 방법은 다음과 같다. 이는 미들웨어를 작성하는 것과 비슷한데 미들웨어가 3개의 인자(req, res, next)를 넘겨주었다면, 에러핸들러는 4개의 인자(err, req, res, next)를 넘겨주어야 한다. 4개의 인자를 넘겨주게 되면, express는 해당 로직이 오류 처리 미들웨어(에러 핸들러)로 인식하게 된다.
// 커스텀에러핸들러
app.use((err, req, res, next)=>{
const {status = 500 } = err
const {message = "Something is wrong"} = err
res.status(status).send(message);
})
에러가 발생하게 되면 우리가 작성한 커스텀에러 핸들러가 작동하게 된다. 위에 작성된 status와 message는 우선 신경 쓰지 말고 보도록 하자. 에러가 발생하게 되면 에러 핸들러가 해당 에러를 잡고서 처리를 해주게 된다. 그렇기 때문에 에러 핸들러는 코드의 끝단에 위치해야 한다. 아래에 나오는 코드들은 모두 커스텀에러 핸들러 보다 위에 작성되어야 하는 코드들이다.
앱 에러 정의하기
// 앱에러에 해당한다.
class AppError extends Error{
constructor(message, status){
super();
this.message=message,
this.status=status;
}
}
module.exports = AppError
우선 에러를 정의해 준다. 해당 에러는 App에 해당하는 에러로 message와 status를 받아서 err에 저장한다. 직접 사용하는 것은 아래와 같다. password가 맞지 않다면 위에서 정의한 에러를 발생시킨다. 에러를 정의할 때 메시지와 상태번호가 있기 때문에 이를 같이 전달해 준다.
const checkPassword = (req,res,next)=>{
const {password} =req.query;
if (password === "password"){
next();
}
// 메시지를 보내는 것이 아닌 에러를 호출할 수 있다.
// 에러 핸들러를 부른다.
throw new AppError("You need Password", 401)
}
throw 된 error는 에러 핸들러에서 잡게 되고서 res.status(status). send(message)를 마지막으로 수행하게 된다. 위에서 status와 message를 디폴트로 500과 "something is wrong"으로 준 이유도 해당 값이 들어오지 않을 시 undfined가 되기 때문이다.
try.... catch
비동기 함수의 경우는 try.. catch구문을 이용해서 오류에 대한 핸들링을 해야 한다. 하지만, express의 경우 많은 함수가 비동기 함수이기 때문에 모든 함수에 try... catch구문을 작성하는 것은 번거롭다. 다음과 같은 방법을 이용해서 처리한다.
// 비동기 콜백을 감싸는 함수를 만들어서 try..catch를 반복해서 사용하지 않게 한다.
// 전체코드가 우리가 정의한 다른 함수로 전달되는 개념이다.
// wrapAsync()에 전달되는 개념이다.
// wrapAsync은 함수를 하나 반환할텐데 그 함수가 로직을 호출한다.
function wrapAsync(fn){
// req,res,next가 필요한 이유는 fn에 전달하기 위해서이다.
return function(req,res,next){
fn(req,res,next).catch(e=> next(e))
}
}
app.get("/products/:id", wrapAsync(async(req, res, next)=>{
const { id } = req.params;
const foundProduct = await Product.findById(id);
if (!foundProduct){
throw new AppError("Not Item", 404);
}
res.render("products/detail", { foundProduct });
}))
mongoose 오류처리
mongoose는 별개로 또 오류가 존재한다. 해당 오류를 어떻게 처리할 것인가 역시 생각해야 하는 주제로, 아래와 같이 정의할 수 있다.
// mongoose 오류 종류별 처리방법
const handleValidationErr = err=>{
return new AppError(`Validation Failed... ${err.message}`, 400)
}
const handleCastErr = err=>{
return new AppError(`Cast Failed... ${err.message}`, 400)
}
app.use((err, req,res,next)=>{
if(err.name==="ValidationError"){
err = handleValidationErr(err);
}
if(err.name==="CastError"){
err = handleCastErr(err);
}
next(err);
})
정리하자면
에러를 다루는 것이 어렵다는 것은 알았으나 아직 이해가 되지 않는다. 사실 복사 붙여넣기한 코드가 많아서 일일이 설명을 할 수 없다. 알았다면 글을 좀 더 구체적으로 적었을 텐데 이해가 딸려서 작성하기가 어렵다. 에러에도 다양한 종류가 있으며 해당 오류를 어떻게 처리할 것인지에 대해서만 대략적으로 알 수 있었던 거 같다.
본글은 잘못된 내용이 포함되어 있습니다.
참고해 주세요
어렵다 어렵다 어렵다 어렵다. 어렵다
'NodeJS.Express.MongoDB' 카테고리의 다른 글
| [mongoose] mongoose의 1:N 관계를 설정해보자!!! (0) | 2023.01.22 |
|---|---|
| [Joi] 유효성 검사를 해 볼까????? 해보자!!!!!! (0) | 2023.01.21 |
| [Express] express는 Middleware가 엄청나게 많다. 와 middleware야 너는 정말 좋겠구나 (1) | 2023.01.20 |
| [nodeJS+Express+mongoose] 연결하자 연결하자!!!! (0) | 2023.01.20 |
| [mongoose] mongoDB를 node에서 사용해보자!!! (0) | 2023.01.17 |