express로 에러를 알리기 위해서는 에러를 던지거나 next()를 사용해야 한다.
그러나 전자에서는 비동기로 에러를 던질 경우 에러를 잡지 못한다.
오류 처리 미들웨어는 맨 아래에 위치해야 한다.
const app = require("express")()
app.get("*", function (req, res, next) {
// 이 미들웨어가 에러를 던지면 익스프레스는 곧바로 다음 오류 처리기로 이동
throw new Error("에러 발생");
})
app.get("*", function (req, res, next) {
// 이전 미들웨어에서 에러가 발생했기 때문에 스킵됨
console.log("this will not print");
})
// 오류 처리 미들웨어(4개의 인자)
app.use(function (error, req, res, next) {
// 이 서버로 들어온 모든 요청은 여기에 올 것이고
// 에러 메세지 '에러 발생'와 함께 HTTP 응답을 보낼 것
res.json({ message: error.message });
})
app.listen(3000)
const app = require("express")()
app.get("*", function (req, res, next) {
setImmediate(() => {
throw new Error("woops")
})
})
app.use(function (error, req, res, next) {
// 위 에러를 잡지 못한다
res.json({ message: error.message })
})
app.listen(3000)
const app = require("express")()
app.get("*", function (req, res, next) {
setImmediate(() => {
next(new Error("woops"))
})
})
app.use(function (error, req, res, next) {
// error가 도달할 수 있다
res.json({ message: error.message })
})
app.listen(3000)
import { Request, Response, NextFunction } from "express";
type AsyncRequestHandler = (
req: Request,
res: Response,
next: NextFunction
) => Promise<any>;
export const wrapAsync = (fn: AsyncRequestHandler) => {
return (req: Request, res: Response, next: NextFunction) => {
// 모든 오류를 .catch() 처리 후 next() 미들웨어에 전달
fn(req, res, next).catch(next);
};
};
import { Request, Response, NextFunction } from "express";
type AsyncRequestHandler = (
req: Request,
res: Response,
next: NextFunction
) => Promise<any>;
export const wrapAsync = (fn: AsyncRequestHandler) => {
return async (req: Request, res: Response, next: NextFunction) => {
try {
await fn(req, res, next);
} catch (error) {
next(error);
}
};
};
export class CustomError extends Error {
statusCode: number;
constructor(message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
}
}
import { HttpCode } from "./HttpCode";
import { CustomError } from "./CustomError";
export class BadRequest extends CustomError {
constructor(message: string) {
// HttpCode는 열거형(enum) 데이터, BAD_REQUEST:400
super(message, HttpCode.BAD_REQUEST);
}
}
import { HttpCode } from "./HttpCode";
import { CustomError } from "./CustomError";
export class InternalServerError extends CustomError {
constructor(message: string) {
super(message, HttpCode.INTERNAL_SERVER_ERROR); // 500
}
}
import { Request, Response, NextFunction } from "express";
import { CustomError } from "../errors/CustomError";
import { BadRequest } from "../errors/BadRequest";
import { InternalServerError } from "../errors/InternalServerError";
export const errorHandler = (
error: Error,
req: Request,
res: Response,
next: NextFunction
) => {
console.error("에러 발생:", error);
if (
error instanceof CustomError ||
error instanceof BadRequest ||
error instanceof InternalServerError // 예상치 못한 서버 오류
) {
res.status(error.statusCode).json({ error: error.message });
} else {
// 일반적인 서버 오류
res.status(500).json({ error: "서버 에러 발생" });
}
};
https://jeonghwan-kim.github.io/node/2017/08/17/express-error-handling.html
https://velog.io/@tmpks5/express-%EC%97%90%EB%9F%AC-%ED%95%B8%EB%93%A4%EB%A7%81-%EB%A1%9C%EC%A7%81-%EB%B6%84%EB%A6%AC-%EB%B0%8F-Custom-Error-%EC%A0%9C%EC%9E%91