Добро пожаловать, чтобы продолжать обращать внимание *NestJs之旅
*Серия статей
Перехватчик — это реализация, котораяNestInterceptorинтерфейс и есть@InjectableКласс, украшенный декоратором.
Interceptor — это приложение, основанное на идеях АОП-программирования.Следующие часто используемые функции:
- Выполняется до или после выполнениядополнительная логика, эта логика вообще не является частью бизнеса
- конвертироватьрезультат выполнения функции
- конвертироватьИсключение возникло во время выполнения функции
- Базовое поведение функций расширения
- Полностью переписать поведение функции в конкретном сценарии (например, перехватчик кеша, который возвращается сразу после того, как есть доступный кеш, без выполнения реальной бизнес-логики, то есть было переписано поведение функции обработки бизнес-логики)
Интерфейс перехватчика
Каждый перехватчик должен реализоватьNestInterceptorМетод **intercept()** интерфейса, который принимает два параметра. Прототип метода выглядит следующим образом:
function intercept(context: ExecutionContext, next: CallHandler): Observable<any>
- Контекст выполнения ExecutionContext сУчебное путешествие NestJ (7) — защита маршрутизациисерединаконтекст выполнениятакой же
- Обработчик маршрута CallHandler
CallHandler
Этот интерфейс является абстракцией функции обработки маршрутизации.Интерфейс определяется следующим образом:
export interface CallHandler<T = any> {
handle(): Observable<T>;
}
Возвращаемое значение функции handle() также является возвращаемым значением соответствующей функции маршрутизации.
В качестве примера возьмем список пользователей приобретения:
// user.controller.ts
@Controller('user')
export class UserController {
@Get()
list() {
return [];
}
}
При доступе к /user/list функция обработки маршрута возвращает **[]** Если перехватчик применен, вызов метода handle() интерфейса CallHandler также получит Observable (объект-оболочку RxJs).
Следовательно, если в перехватчике будет вызван метод next.handle(), то соответствующая функция обработки маршрута будет выполнена, а если не вызвана, то не будет выполнена.
Перехватчик регистрации ссылок запросов
С появлением микросервисов исходный единый проект разбивается на несколько более мелких подмодулей.Эти подмодули можно независимо разрабатывать, развертывать и запускать независимо, что значительно повышает эффективность разработки и выполнения, но также приводит к проблемам.Чаще всего , часто встречающаяся проблема заключается в том, что трудно найти журнал при сбое вызова интерфейса.
Крайне нецелесообразно жестко кодировать такой журнал вызовов ссылок в бизнес-логике, что серьезно нарушает принцип единой ответственности.Эта логика может быть реализована полностью через перехватчики.
// app.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Request } from 'express';
import { format } from 'util';
@Injectable()
export class AppInterceptor implements NestInterceptor {
private readonly logger = new Logger(); // 实例化日志记录器
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const start = Date.now(); // 请求开始时间
return next.handle().pipe(tap((response) => {
// 调用完handle()后得到RxJs响应对象,使用tap可以得到路由函数的返回值
const host = context.switchToHttp();
const request = host.getRequest<Request>();
// 打印请求方法,请求链接,处理时间和响应数据
this.logger.log(format(
'%s %s %dms %s',
request.method,
request.url,
Date.now() - start,
JSON.stringify(response),
));
}));
}
}
// user.controller.ts
@UseInterceptors(AppInterceptor)
export class UserController {
@Get()
list() {
return [];
}
}
Консоль хочет выводить при доступе к /user
[Nest] 96310 - 09/10/2019, 2:44 PM GET /user 1ms []
Объем перехватчика
Перехватчик может привязать следующую область:
- глобальный перехватчик
- перехватчик контроллера
- Перехватчик метода маршрутизации
глобальный перехватчик
Просто используйте следующий код в main.ts:
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new AppInterceptor());
перехватчик контроллера
будет принадлежать контроллерумаршрутизацияМетод вступает в силу:
@Controller('user')
@UseInterceptors(AppInterceptor)
export class UserController {
}
Перехватчик метода маршрутизации
Перехватывать только текущий декорированный метод маршрутизации:
@Controller('user')
export class UserController {
@UseInterceptors(AppInterceptor)
@Get()
list() {
return [];
}
}
Обработка ответа
Возвращаемое значение handle() интерфейса CallHandler на самом деле является наблюдаемым объектом RxJs. Объектом можно управлять с помощью оператора RxJs. Например, существует интерфейс API. Ранее возвращаемая структура данных выглядит следующим образом. ответ нормальный, тело ответа это данные.Структура упаковки:
{
"id":1,
"name":"xialei"
}
Новое требование состоит в том, чтобы обернуть предыдущий ответ с чистыми данными в атрибут данных со следующей структурой:
{
"data": {
"id": 1,
"name":"xialei"
}
}
При получении этого запроса некоторые мелкие партнеры, возможно, уже разбирали количество интерфейсов ответа, а затем оценивали человеко-часы для подготовки к разработке.Используя перехватчик NestJ, это требование может быть реализовано менее чем за палочку благовоний.
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class AppInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().
pipe(map(data => ({ data }))); // map操作符与Array.prototype.map类似
}
}
После применения вышеуказанного перехватчика данные ответа будут обернуты слоем атрибута данных.
отображение исключений
Еще одним интересным примером является использование catchError RxJs для переопределения исключений, генерируемых обработчиками маршрутов.
import {
Injectable,
NestInterceptor,
ExecutionContext,
BadGatewayException,
CallHandler,
} from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class ErrorsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next
.handle()
.pipe(
catchError(err => throwError(new BadGatewayException())) // catchError用来捕获异常
);
}
}
Переписывание функции логики маршрутизации
В начале статьи упоминалось, что перехватчик может переопределить логику обработчика маршрутизации. Ниже приведен пример перехватчика буфера.
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable, of } from 'rxjs';
@Injectable()
export class CacheInterceptor implements NestInterceptor {
constructor(private readonly cacheService: CacheService) {}
async intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const host = context.switchToHttp();
const request = host.getRequest();
if(request.method !== 'GET') {
// 非GET请求放行
return next.handle();
}
const cachedData = await this.cacheService.get(request.url);
if(cachedData) {
// 命中缓存,直接放行
return of(cachedData);
}
return next.handle().pipe(tap(response) => {
// 响应数据写入缓存,此处可以等待缓存写入完成,也可以不等待
this.cacheService.set(request.method, response);
});
}
}
конец
Эта статья является последней из основ NestJ и будет обновляться для конкретных модулей, таких как база данных, загрузка, аутентификация и т. д.
Из-за прямого выпуска группового QR-кода порог для вступления в группу крайне низок.В последнее время некоторые бездельники сканировали код для входа в группу для отправки рекламы/вредоносной информации, серьезно беспокоя участников группы, и QR канал ввода кодовой группы был закрыт. Нуждающиеся партнеры могут подписаться на официальный аккаунт, чтобы получить квалификацию для присоединения к группе.