- 소프트웨어를 처리하면서 예외(exception)처리는 필수 사항이다.
- 어떤 상황에서든 에러는 발생할 수 있고, 개발자는 이 에러에 대응책을 마련해 두어야 한다.
- Nest는 프레임 워크 내에 예외 레이어를 두고 있다.
- 애플리케이션을 통틀어 제대로 처리하지 못한 예외를 처리하는 역할을 한다.
- 이는 우리가 아무런 작업을 하지 않아도, 기본 예외 처리기가 예외를 잡아서 유저가 이해하기 쉬운 형태로 변환하여 전송한다.
$ curl http://localhost:3000/error
{
"statusCode":500,
"message":"Internal Server Error"
}
- Nest는 예외에 대한 많은 클래스를 제공한다.
- 위 결과를 보면 에러가 발생했을때 응답을 Json 형식으로 바꿔주고 있는데, 이는 기본으로 내장된 전역 예외 필터가 처리한다.
- 내장 예외 필터는 인식할 수 없는 에러를 다음과 같이 "Internal Server Error Exception"으로 변환한다.
- MDN 문서에 따르면 500InternalServerError는 "요청을 처리하는 과정에서 서버가 예상하지 못한 상황에 놓였다는 것을 나타낸다" 라고 되어 있다.
- "Internal Server Error Exception"의 선언을 보면 HttpException을 상속받고 있고, HttpException은 다시 JS의 Error를 상속한다.
- 결국 모든 예외는 Error 객체로부터 파생된 것을 알 수 있다.
예외 처리
- 그 외 Nest에서 제공하는 모든 에외 역시 HttpException을 사용하고 있다.
- 이 예외 클래스들을 이용해서 상황에 따라 적절한 예외를 던지면 된다.
- 적절한 예외 처리는 API를 호출한 클라이언트에서 에러를 쉽게 이해하고 대처할 수 있도록 한다.
- 예외처리를 발생시키는 방법은 다음과 같다.
throw new HttpException(
{
"statusCode" : 400,
"message": " 잘못된 값이 들어온것 같습니다.",
"error": "id format exception
}
)
- 이 이외에 Nest에서 제공하는 표준 예외들은 MDN 문서를 참고하면 된다.
• BadRequestException
잘못된 요청(Bad Request)이 일어날 경우 발생하는 예외입니다. 이 예외는 요청 메시지가 올바른 형식이 아닌 경우, 필수 파라미터가 누락되었거나 잘못된 값이 전달된 경우 등에 발생합니다. 이 예외를 처리하는 것은 클라이언트가 정확한 요청을 만들어 전송하도록 강요하는 것입니다
• UnsupportedMediaTypeException
UnsupportedMediaTypeException은 요청에 전달된 미디어 타입이 서버에서 지원되지 않는 경우 발생하는 예외입니다. 예를 들어, 클라이언트가 서버에 JSON 형식의 데이터를 전송하려고 하지만 서버에서는 XML 형식만 지원하는 경우 발생할 수 있습니다. 이 예외가 발생할 경우 클라이언트와 서버간의 협업이 필요하며, 클라이언트는 서버에서 지원하는 미디어 타입으로 요청을 다시 전송해야 합니다.
• UnauthorizedException
UnauthorizedException은 요청이 인증되지 않은 경우 발생하는 예외입니다. 이 예외는 클라이언트가 제공한 인증 정보(예를 들어, 사용자 이름과 비밀번호)가 유효하지 않은 경우, 권한이 없는 경우 등에 발생합니다. 이 예외를 처리하는 것은 클라이언트가 올바른 인증 정보를 제공하도록 강요하는 것입니다.
• UnprocessableEntityException
UnprocessableEntityException은 요청의 구조가 올바르지 않은 경우 발생하는 예외입니다. 이 예외는 클라이언트가 제공한 데이터가 기대한 형식과 맞지 않는 경우, 필수 필드가 빠진 경우 등에 발생합니다. 이 예외는 클라이언트에게 제공하는 오류 메시지를 통해 클라이언트가 올바른 데이터를 제공하도록 지침을 제공할 수 있습니다.
• NotFoundException
NotFoundException은 클라이언트가 요청한 리소스가 서버에서 찾을 수 없을 때 발생하는 예외입니다. 이 예외는 클라이언트가 요청한 URL이 올바르지 않거나, 서버에서 요청한 리소스가 삭제되었거나, 아직 생성되지 않았을 때 발생합니다. 이 예외를 처리하는 것은 클라이언트에게 올바른 리소스를 찾도록 돕는 것입니다.
• InternalServerErrorException
InternalServerErrorException은 서버에서 예기치 않은 오류가 발생했을 때 발생하는 예외입니다. 이 예외는 서버에서 발생한 오류로 인해 클라이언트의 요청을 처리할 수 없을 때 발생합니다. 예를 들어, 데이터베이스 서버에서 오류가 발생하거나, 메모리 부족 등의 원인으로 오류가 발생할 때 이 예외가 발생합니다. 이 예외는 클라이언트에게 오류가 발생했음을 알리고, 개발자에게 디버깅을 돕도록 제공합니다.
• ForbiddenException
ForbiddenException은 클라이언트가 요청한 리소스에 대한 접근 권한이 없을 때 발생하는 예외입니다. 이 예외는 클라이언트가 인증되지 않았거나, 특정 리소스에 대한 접근 권한이 없거나, 관리자에 의해 리소스에 대한 접근이 금지되었을 때 발생합니다. 이 예외를 처리하는 것은 클라이언트에게 적절한 접근 권한이 있는 리소스를 찾도록 돕는 것입니다.
• NotImplementedException
NotImplementedException은 특정 메소드나 기능이 구현되지 않았을 때 발생하는 예외입니다. 이 예외는 개발자가 아직 구현하지 않은 부분이 있거나, 구현되지 않은 API를 호출하려고 할 때 발생합니다. 이 예외는 클라이언트에게 구현되지 않은 기능을 사용하지 마라는 것을 알려주는 역할을 합니다.
• NotAcceptableException
NotAcceptableException은 클라이언트가 요청한 컨텐츠 타입이나 버전을 서버가 지원하지 않을 때 발생하는 예외입니다. 이 예외는 클라이언트가 요청한 리소스가 서버에서 처리할 수 없음을 나타냅니다. 예를 들어, 클라이언트가 JSON 포맷의 데이터를 요청하지만 서버가 XML만 지원할 때 발생할 수 있습니다. 이 예외는 클라이언트에게 지원하지 않는 컨텐츠 타입을 요청하지 마라는 것을 알려주는 역할을 합니다.
• ImATeapotException
"418 I'm a teapot" 오류는 HTTP 확장 프레임워크에 특화된 HTTP 상태 코드입니다. 이 오류 코드는 1998년에 Hypertext Coffee Pot Control Protocol(HTCPCP)의 일부로 정의되었습니다. HTCPCP는 HTTP 프로토콜의 유머적인 확장으로, 실제 웹 서버에서 구현하려는 것이 아니라 유머적인 목적으로만 정의되었습니다.
이 오류 코드는 클라이언트가 차를 끓이려고 했을 때 발생하며, 서버에서 해당 요청을 처리할 수 없음을 나타냅니다.
실제로는 이 오류 코드는 거의 사용되지 않으며, 대부분의 현대적인 웹 서버는 이 오류 코드를 사용하는 요청에 대해 "400 Bad Request" 오류를 반환할 것입니다.
• RequestTimeoutException
"RequestTimeoutException"은 클라이언트의 서버 요청이 완료되기까지 너무 오래 걸려서 서버가 응답을 기다리지 않을 때 발생하는 오류입니다. 이 오류는 느린 네트워크 연결이나 바쁜 서버로 인해 요청을 시간적으로 처리할 수 없는 경우 등 다양한 이유로 발생할 수 있습니다.
서버가 RequestTimeoutException을 만나면, "408 Request Timeout" HTTP 상태 코드를 반환할 수 있습니다. 이는 서버가 클라이언트의 완전한 요청을 서버가 기다리는 시간 내에 받지 못했음을 나타냅니다. 클라이언트는 그 다음에 요청을 다시 보내거나 기타 적절한 조치를 취할 수 있습니다.
경우에 따라 클라이언트에서 RequestTimeout이 발생할 수도 있습니다서버가 응답을 보내는 데 너무 오래 걸리는 경우 예외입니다. 이 경우 클라이언트는 요청을 다시 시도하거나 다른 적절한 조치를 취할 수 있습니다.
• MethodNotAllowedException
MethodNotAllowedException은 요청한 리소스에 대한 HTTP 메소드가 허용되지 않음을 나타내는 예외입니다. 예를 들어, 웹 서버에서 PUT 메소드를 지원하지 않는 리소스에 PUT 요청을 하면 이 예외가 발생할 수 있습니다.
• ConflictException
ConflictException은 요청한 작업이 충돌하여 수행할 수 없음을 나타내는 예외입니다. 예를 들어, 웹 서버에서 동일한 리소스에 대해 두 개의 요청이 동시에 들어오면 이 예외가 발생할 수 있습니다. 충돌이 일어난 경우, 서버는 어떤 요청을 수행할지에 대한 결정을 해야 할 수도 있습니다.
• BadGatewayException
BadGatewayException은 중계 서버에서 예상치 못한 오류가 발생하여 요청을 처리할 수 없음을 나타내는 예외입니다. 예를 들어, 클라이언트가 웹 서버를 통해 다른 서버에 요청을 하는 경우, 중계 서버가 다른 서버와의 통신에 문제가 있을 때 이 예외가 발생할 수 있습니다.
• GoneException
GoneException은 요청한 리소스가 영구적으로 삭제되어 제공할 수 없음을 나타내는 예외입니다. 이 예외가 발생하면, 클라이언트는 더 이상 요청한 리소스를 얻을 수 없으며, 서버는 리소스가 삭제된 이유와 관련된 정보를 제공할 수 있습니다. 이 예외는 일반적으로 오래된 리소스에 대해 발생하며, 새로운 리소스로 대체될 수 있는 경우가 아니기 때문에 클라이언트는 새로운 요청을 하지 않도록 알려져야 합니다.
• ServiceUnavailableException
ServiceUnavailableException은 서버가 현재 요청을 처리할 수 없는 상태인 경우 발생하는 예외입니다. 이 예외는 서버에 부하가 많이 걸리거나 점검 중이거나, 서버의 자원이 부족하거나, 장애 등의 원인으로 서비스를 제공할 수 없는 경우 발생합니다. 이 예외가 발생하면, 클라이언트는 잠시 후에 다시 요청하거나, 다른 서버에 요청을 할 수 있습니다. 서버는 이 예외가 발생한 원인과 언제 서비스가 복구될 예정인지에 대한 정보를 제공할 수 있습니다.
• HttpVersionNotSupportedException
HttpVersionNotSupportedException은 클라이언트가 요청한 HTTP 버전이 서버에서 지원되지 않는 경우 발생하는 예외입니다. 예를 들어, 클라이언트가 HTTP/1.1을 사용하여 요청을 하지만, 서버에서는 HTTP/1.0만 지원하는 경우에 이 예외가 발생할 수 있습니다. 이 예외가 발생할 경우, 클라이언트는 지원되는 HTTP 버전으로 요청을 다시 해야 합니다.
• PayloadTooLargeException
PayloadTooLargeException은 클라이언트가 전송하는 데이터의 크기가 서버에서 허용되는 최대 크기를 초과할 경우 발생하는 예외입니다. 이 예외가 발생할 경우, 클라이언트는 데이터의 크기를 줄이거나 서버에서 최대 허용 크기를 늘려야 합니다.
• GatewayTimeoutException
GatewayTimeoutException은 게이트웨이가 지정된 시간 동안 요청을 처리하지 못할 경우 발생하는 예외입니다. 이 예외는 게이트웨이에서 다른 시스템과의 통신이 지연되어 요청 처리에 필요한 시간이 너무 길어져 생기는 문제를 나타냅니다. 이 예외가 발생할 경우, 클라이언트는 요청을 다시 시도하거나 게이트웨이에서 설정된 시간을 늘려야 합니다.
• PreconditionFailedException
PreconditionFailedException은 클라이언트가 요청에 대한 사전 조건을 만족하지 못할 경우 발생하는 예외입니다. 이 예외는 서버에서 수행하는 리소스 변경 작업을 안전하게 처리하기 위해 클라이언트가 제시한 조건이 서버에서 처리 가능한 상태인지 확인하는 데 사용됩니다. 이 예외가 발생할 경우, 클라이언트는 상태를 업데이트하거나 새로운 조건을 제시하여 요청을 다시 시도해야 합니다.
에외 필터
- Nest에서 직접 제공하는 전역 예외 필터 외에 직접 예외 필터(exception filter) 레이어를 둬, 원하는 대로 예외를 다룰 수 있따.
- 예외가 일어났을 때 로그를 남기거나 응답 객체를 원하는 대로 변경하고 하는 등의 요구 사항을 해결하고자 할 때 사용한다.
- 다음은 예외가 발생했을 때 모든 예외(Error)를 잡아서 요청 URL과 예외가 발생한 시각을 콘솔에 출력하는 예외 필터를 만든 코드이다.
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
InternalServerErrorException,
} from '@nestjs/common';
import { Request, Response } from 'express';
// Catch 데커레이터는 처리되지 않은 모든 예외를 잡으려고 할때 사용한다.
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
// 예외가 발생한다면
catch(exception: any, host: ArgumentsHost) {
// switchToHttp() 메소드를 사용하여 ExpressJs의 req와 res 객체에 엑세스 할 수 있다.
const ctx = host.switchToHttp();
// 그런다음 getResponse() 메소드와 getRequest()메소드를 사용하여 Response와 Request 객체에 엑세스한다.
const res = ctx.getResponse<Response>();
const req = ctx.getRequest<Request>();
// 예외가 HttpException의 인스턴스가 아니면, InternalServerErrorException을 새로 생성한다.
if (!(exception instanceof HttpException)) {
exception = new InternalServerErrorException();
}
// 그런 다음, getResponse() 메소드를 사용하여 HTTP 응답 메시지를 가져오고
const response = (exception as HttpException).getResponse();
const log = {
timestamp: new Date(),
url: req.url,
response,
};
console.log(log);
//getStatus메소드를 사용하여 HTTP 상태 코드를 가져 온다.
// 마지막으로 상태 코드와 HTTP 응답 메시지를 설정한 다음. json형식으로 응답한다.
// 또한 URL, 타임스탬프, HTTP 응답을 포함하는 로그 객체를 출력한다.
res.status((exception as HttpException).getStatus()).json(response);
}
}
** switchToHttp()**
- 'switchToHttp' 메소드는 NestJS에서 'ArgumentsHost' 객체의 HTTP 컨텍스트를 가져오는데 사용되는 메소드이다.
- 이 메소드를 사용하면 현재 HTTP 요청과 응답에 대한 정보에 접근할 수 있다.
- 예를 들어 switchToHttp메소드를 사용하여 현재 HTTP 요청에 접근하려면 다음과 같이 할 수 있다.
const ctx = host.switchToHttp();
const req = ctx.getRequest<Request>();
const res = ctx.getResponse<Response>();
- 이제 예외 필터를 만들었으니 적용을 해보면 된다.
- 예외 필터는 @UseFilter데커레이터로 컨트롤러에 직접 적용하거나, 전역으로 적용할 수 있다.
- 예외필터는 전역 필터를 하나만 가지도록 하는 것이 일반적이다.
1. 특정 엔트포인트(컨트롤러)에 적용할 때
@UseFilters(HttpExceptionFilter)
@Post('/save')
async createUser(@Body(ValidationPipe) dto: CreateUserDto): Promise<void> {
const { name, email, password } = dto;
2. 특정 컨트롤러 전체에 적용할 때
@Controller('users')
@UseFilters(HttpExceptionFilter)
export class UsersController {
constructor(
private userService: UsersService,
private authService: AuthService,
3. 애플리케이션 전체에 적용할 때
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
'Back-End > Nest.js' 카테고리의 다른 글
인터셉터 (0) | 2023.02.22 |
---|---|
내장 로거 (0) | 2023.02.13 |
파이프와 유효성 검사 (0) | 2023.02.01 |
동적 모듈을 활용한 환경 변수 구성 (0) | 2023.01.25 |
멋사 2주차 JS decorator, MVC 패턴, Nest.js 찍먹 (0) | 2023.01.11 |