Фільтры выключэнняў
Nest пастаўляецца з убудаваным узроўнем выключэнняў , які адказвае за апрацоўку ўсіх неапрацаваных выключэнняў у дадатку. Калі выключэнне не апрацоўваецца кодам вашага прыкладання, яно ўлоўліваецца гэтым узроўнем, які затым аўтаматычна адпраўляе адпаведны зручны адказ.
Нестандартна гэта дзеянне выконваецца з дапамогай убудаванага глабальнага фільтра выключэнняў , які апрацоўвае выключэнні тыпу HttpException
(і яго падкласы). Калі выключэнне не распазнана (не з'яўляецца ні HttpException
, ні класам, які ўспадкоўвае ад HttpException
), убудаваны фільтр выключэнняў стварае наступны адказ JSON па змаўчанні:
{
"statusCode": 500,
"message": "Internal server error"
}
http-errors
. Па сутнасці, любое выключанае выключэнне, якое змяшчае ўласцівасці statusCode
і message
будзе належным чынам запаўняцца і адпраўляцца назад у якасці адказу (замест стандартнага InternalServerErrorException
для нераспазнаных выключэнняў). :::Выкід стандартных выключэнняў
Nest забяспечвае ўбудаваны клас HttpException
, адкрыты з пакета @nestjs/common
. Для тыповых прыкладанняў, заснаваных на HTTP REST/GraphQL API, пры ўзнікненні пэўных памылак лепш за ўсё адпраўляць стандартныя аб'екты адказу HTTP.
Напрыклад, у CatsController
у нас ёсць метад findAll()
(апрацоўшчык маршруту GET
). Давайце выкажам здагадку, што гэты апрацоўшчык маршруту па нейкай прычыне стварае выключэнне. Каб прадэманстраваць гэта, мы жорстка закадзіруем гэта наступным чынам:
@@filename(cats.controller)
@Get()
async findAll() {
throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
}
HttpStatus
. Гэта дапаможны пералік, імпартаваны з пакета @nestjs/common
. :::Калі кліент выклікае гэтую канчатковую кропку, адказ выглядае так:
{
"statusCode": 403,
"message": "Forbidden"
}
Канструктар HttpException
прымае два неабходныя аргументы, якія вызначаюць адказ:
- Аргумент
response
вызначае цела адказу JSON. Гэта можа быцьstring
абоobject
, як апісана ніжэй. - Аргумент
status
вызначае код стану HTTP .
Па змаўчанні цела адказу JSON змяшчае дзве ўласцівасці:
statusCode
: па змаўчанні выкарыстоўваецца код стану HTTP, указаны ў аргументеstatus
message
: кароткае апі санне памылкі HTTP на асновеstatus
Каб перавызначыць толькі частку паведамлення ў целе адказу JSON, увядзіце радок у аргумент response
. Каб перавызначыць увесь тэкст адказу JSON, перадайце аб'ект у аргумент response
. Nest серыялізуе аб'ект і верне яго як цела адказу JSON.
Другі аргумент канструктара - status
- павінен быць сапраўдным кодам стану HTTP. Найлепшая практыка - выкарыстоўваць пералік HttpStatus
, імпартаваны з @nestjs/common
.
Ёсць трэці аргумент канструктара (неабавязковы) - options
- які можна выкарыстоўваць для вызначэння прычыны памылкі. Гэты аб'ект cause
не серыялізаваны ў аб'ект адказу, але ён можа быць карысны для мэт вядзення часопіса, даючы каштоўную інфармацыю аб унутранай памылцы, якая выклікала выключэнне HttpException
.
Вось прыклад перавызначэння ўсяго цела адказу і ўказання прычыны памылкі:
@@filename(cats.controller)
@Get()
async findAll() {
try {
await this.service.findAll()
} catch (error) {
throw new HttpException({
status: HttpStatus.FORBIDDEN,
error: 'This is a custom message',
}, HttpStatus.FORBIDDEN, {
cause: error
});
}
}
Выкарыстоўваючы вышэйсказанае, вось як будзе выглядаць адказ:
{
"status": 403,
"error": "This is a custom message"
}
Карыстальніцкія выключэнні
У многіх выпадках вам не трэба будзе пісаць карыстальніцкія выключэнні, і вы можаце выкарыстоўваць убудаванае выключэнне Nest HTTP, як апісана ў наступным раздзеле. Калі вам трэба стварыць наладжвальныя выключэнні, добрай практыкай будзе стварыць уласную іерархію выключэнняў , дзе вашы наладжвальныя выключэнні ўспадкуюць ад базавага класа HttpException
. Пры такім падыходзе Nest распазнае вашы выключэнні і аўтаматычна паклапоціцца пра адказы на памылкі. Давайце рэалізуем такое карыстацкае выключэнне:
@@filename(forbidden.exception)
export class ForbiddenException extends HttpException {
constructor() {
super('Forbidden', HttpStatus.FORBIDDEN);
}
}
Паколькі ForbiddenException
пашырае базавы HttpException
, ён будзе бесперашкодна працаваць з убудаваным апрацоўшчыкам выключэнняў, і таму мы можам выкарыстоўваць яго ўнутры метаду findAll()
.
@@filename(cats.controller)
@Get()
async findAll() {
throw new ForbiddenException();
}
Убудаваныя выключэнні HTTP
Nest забяспечвае набор стандартных выключэнняў, якія ўспадкоўваюцца ад базавага HttpException
. Яны прадстаўлены з пакета @nestjs/common
і ўяўляюць сабой многія найбольш распаўсюджаныя выключэнні HTTP:
BadRequestException
UnauthorizedException
NotFoundException
ForbiddenException
NotAcceptableException
RequestTimeoutException
ConflictException
GoneException
HttpVersionNotSupportedException
PayloadTooLargeException
UnsupportedMediaTypeException
UnprocessableEntityException
InternalServerErrorException
NotImplementedException
ImATeapotException
MethodNotAllowedException
BadGatewayException
ServiceUnavailableException
GatewayTimeoutException
PreconditionFailedException
Усе ўбудаваныя выключэнні таксама могуць даць як cause
памылкі, так і апісанне памылкі з дапамогай параметра options
:
throw new BadRequestException('Something bad happened', { cause: new Error(), description: 'Some error description' })
Выкарыстоўваючы вышэйсказанае, вось як будзе выглядаць адказ:
{
"message": "Something bad happened",
"error": "Some error description",
"statusCode": 400,
}
Фільтры выключэнняў
У той час як базавы (убудаваны) фільтр выключэнняў можа аўтаматычна апрацоўваць многія выпадкі за вас, вам можа спатрэбіцца поўны кантроль над узроўнем выключэнняў. Напрыклад, вы можаце дадаць вядзенне журналаў або выкарыстоўваць іншую схему JSON на аснове некаторых дынамічных фактараў. Фільтры выключэнняў прызначаны менавіта для гэтай мэты. Яны дазваляюць кантраляваць дакладны паток кіравання і змест адказу, адпраўленага кліенту.
Давайце створым фільтр выключэнняў, які адказвае за перахоп выключэнняў, якія з'яўляюцца асобнікамі класа HttpException
, і рэалізацыю карыстацкай логікі адказу для іх. Для гэтага нам спатрэбіцца атрымаць доступ да аб'ектаў Request
і Response
базавай платформы. Мы атрымаем доступ да аб'екта Request
, каб атрымаць зыходны url
і ўключыць яго ў інфармацыю для рэгістрацыі. Мы будзем выкарыстоўваць аб'ект Response
для непасрэднага кантролю над адпраўленым адказам з дапамогай метаду response.json()
.
@@filename(http-exception.filter)
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
@@switch
import { Catch, HttpException } from '@nestjs/common';
@Catch(HttpException)
export class HttpExceptionFilter {
catch(exception, host) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
ExceptionFilter<T>
. Гэта патрабуе ад вас падаць метад catch(exception: T, host: ArgumentsHost)
з указанай сігнатурай. T
паказвае тып выключэння. :::@nestjs/platform-fastify
вы можаце выкарыстоўваць response.send()
замест response.json()
. Не забудзьцеся імпартаваць правільныя тыпы з fastify
. :::Дэкаратар @Catch(HttpException)
звязвае неабходныя метаданыя з фільтрам выключэнняў, паведамляючы Nest, што гэты канкрэтны фільтр шукае выключэнні тыпу HttpException
і нічога іншага. Дэкаратар @Catch()
можа прымаць адзін параметр або спіс, падзелены коскамі. Гэта дазваляе наладзіць фільтр адначасова для некалькіх тыпаў выключэнняў.
Аргументы гаспадара
Давайце паглядзім на параметры метаду catch()
. Параметр exception
- гэта аб'ект выключэння, які зараз апрацоўваецца. Параметр host
- гэта аб'ект ArgumentsHost
. ArgumentsHost
- гэта магутны ўтылітны аб'ект, які мы разгледзім далей у раздзеле аб кантэксце выканання *. У гэтым узоры кода мы выкарыстоўваем яго для атрымання спасылкі на аб'екты Request
і Response
, якія перадаюцца першапачатковаму апрацоўшчыку запытаў (у кантролеры, дзе ўзнікае выключэнне). У гэтым узоры кода мы выкарыстоўвалі некаторыя дапаможныя метады на ArgumentsHost
, каб атрымаць жаданыя аб'екты Request
і Response
. Даведайцеся больш пра ArgumentsHost
тут .
*Прычына гэтага ўзроўню абстракцыі заключаецца ў тым, што ArgumentsHost
функцыянуе ва ўсіх кантэкстах (напрыклад, у кантэксце HTTP-сервера, з якім мы зараз працуем, а таксама ў мікрасэрвісах і WebSockets). У раздзеле аб кантэксце выканання мы паглядзім, як мы можам атрымаць доступ да адпаведных асноўных аргументаў для любога кантэксту выканання з дапамогай магутнасці ArgumentsHost
і яго дапаможных функцый. Гэта дазволіць нам напісаць агульныя фільтры выключэнняў, якія працуюць ва ўсіх кантэкстах.