Skip to content
On this page

安装

js
npm install --save @nestjs/common  @nestjs/core  express-session  reflect-metadata @nestjs/platform-express rxjs cli-color
npm install  --save-dev nodemon  ts-node tsconfig-paths typescript
包名介绍
@nestjs/commonNestJS的公共模块,包含各种装饰器、工具函数和中间件,用于构建NestJS应用程序的核心功能。
@nestjs/coreNestJS的核心模块,提供创建NestJS应用程序的基础设施,包括依赖注入、模块系统等。
express-session用于Express框架的会话中间件,支持会话数据的存储和管理。
reflect-metadata用于在TypeScript和JavaScript中实现反射的库,支持元数据的定义和读取。
rxjsReactive Extensions for JavaScript,提供基于Observable的响应式编程库。
nodemon一个Node.js工具,用于在检测到文件更改时自动重新启动应用程序。
ts-node一个TypeScript执行引擎,允许直接运行TypeScript代码而无需预先编译。
tsconfig-paths一个工具,用于解析TypeScript配置文件中的路径映射,支持模块路径的别名。
typescriptTypeScript编程语言的编译器,提供静态类型检查和最新的JavaScript特性。

2.启动项目

2.1 app.controller.ts

src\app.controller.ts

js
// 从 @nestjs/common 模块中导入 Controller 和 Get 装饰器
import { Controller, Get} from '@nestjs/common';
// 使用 Controller 装饰器标记 AppController 类为控制器
@Controller()
export class AppController {
  // 使用 Get 装饰器标记 index 方法为 HTTP GET 路由处理程序
  @Get()
  index(): string {
    // 返回字符串 'Hello'
    return 'Hello';
  }
}

2.2 app.module.ts

src\app.module.ts

js
// 从 @nestjs/common 模块中导入 Module 装饰器
import { Module } from '@nestjs/common';
// 从当前目录导入 AppController 控制器
import { AppController } from './app.controller';
// 使用 @Module 装饰器定义一个模块
@Module({
  // 在模块中注册控制器
  controllers: [AppController],
})
// 定义并导出 AppModule 模块
export class AppModule {}

2.3 main.ts

src\main.ts

js
// 从 @nestjs/core 模块中导入 NestFactory 用于创建 Nest 应用程序
import { NestFactory } from '@nestjs/core';
// 导入应用程序的主模块
import { AppModule } from './app.module';
// 导入 express-session 中间件,用于管理会话
import session from 'express-session';
// 定义一个异步的启动函数
async function bootstrap() {
  // 创建一个 Nest 应用程序实例,传入主模块
  const app = await NestFactory.create(AppModule);
  // 使用 express-session 中间件来管理会话
  app.use(session({
    // 定义用于加密会话的密钥
    secret: 'your-secret-key',
    // 在每次请求结束时是否强制保存会话,即使它没有变化
    resave: false,
    // 是否在未初始化时保存会话
    saveUninitialized: false,
    // 定义会话的 cookie 配置
    cookie: {
      // 设置 cookie 的最大存活时间为一天(以毫秒为单位)
      maxAge: 1000 * 60 * 60 * 24,
    },
  }));
  // 启动应用程序,监听 3000 端口
  await app.listen(3000);
}
// 调用启动函数,启动应用程序
bootstrap();

2.4 tsconfig.json

js
{
    "compilerOptions": {
      "module": "commonjs",
      "declaration": true,
      "removeComments": true,
      "emitDecoratorMetadata": true,
      "experimentalDecorators": true,
      "allowSyntheticDefaultImports": true,
      "esModuleInterop": true,
      "target": "ES2021",
      "sourceMap": true,
      "outDir": "./dist",
      "incremental": true,
      "skipLibCheck": true,
      "strictNullChecks": false,
      "noImplicitAny": false,
      "strictBindCallApply": false,
      "forceConsistentCasingInFileNames": false,
      "noFallthroughCasesInSwitch": false,
      "baseUrl": "./",
      "paths": {
        "@nestjs/*": ["src/@nestjs/*"]
      }
    }
  }

2.5 nodemon.json

js
{
    "watch": [
        "src"
    ],
    "ext": "ts,js,json",
    "ignore": [
        "node_modules"
    ],
    "exec": "ts-node -r tsconfig-paths/register src/main.ts"
}
  • 作用: 指定 nodemon 需要监视的目录或文件,当这些目录或文件发生变化时,nodemon 会自动重启应用程序。
  • "watch": ["src"]: 表示 nodemon 将监视 src 目录中的所有文件和子目录。
  • "ext": "ts,js,json": 表示 nodemon 将监视具有 .ts、.js 和 .json 扩展名的文件。
  • "ignore": ["node_modules"]: 表示 nodemon 将忽略 node_modules 目录中的所有文件和子+ 目录。
  • "ts-node -r tsconfig-paths/register src/main.ts": 表示 nodemon 将使用 ts-node 执+ 行 src/main.ts 文件,并在执行前预加载 tsconfig-paths/register 模块以支持路径映射。
  • 综上,nodemon.json 文件的配置使得 nodemon 工具会监视 src 目录中的 .ts、.js 和 .+ json 文件的变化,忽略 node_modules 目录,并在文件变化时自动使用 ts-node 执行 src/main.ts 文件。

2.6 package.json

js
{
  "scripts": {
    "start": "ts-node -r tsconfig-paths/register ./src/main.ts",
    "start:dev": "nodemon"
  },
}
  • ts-node: 这是一个用于直接运行 TypeScript 代码的工具,它允许在不预先编译的情况下运+ 行 .ts 文件。
  • -r tsconfig-paths/register: 这里的 -r 是 --require 的缩写,用于在执行脚本之前预加+ 载模块。tsconfig-paths/register 模块用于处理 TypeScript 配置中的路径映射。
  • ./src/main.ts: 这是应用程序的入口文件。ts-node 将运行这个 TypeScript 文件。

2.7 launch.json

.vscode\launch.json

js
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "runtimeExecutable": "ts-node",
            "runtimeArgs": [
                "-r",
                "tsconfig-paths/register"
            ],
            "args": [
                "${workspaceFolder}/src/main.ts"
            ],
            "cwd": "${workspaceFolder}"
        }
    ]
}
  • version: 指定配置文件的版本。
  • configurations: 包含一个或多个调试配置,每个配置定义了一种调试场景。
  • type: 指定调试器类型。
  • request: 指定调试请求类型。 "launch": 表示启动程序并进行调试。
  • name: 指定此配置的名称,在调试配置下拉菜单中显示。
  • skipFiles: 指定调试时应跳过的文件或文件夹。
  • runtimeExecutable: 指定要使用的运行时可执行文件。 "ts-node": 使用 ts-node 直接运+ 行 TypeScript 代码。
  • runtimeArgs: 指定运行时的参数。
    • "-r": 表示在执行脚本之前预加载模块。
    • "tsconfig-paths/register": 预加载 tsconfig-paths/register 模块以支持路径映射。
  • args: 指定要调试的程序的参数。
    • ${workspaceFolder}/src/main.ts: 表示要调试的 TypeScript 文件的路径,其中 ${workspaceFolder} 表示当前工作区的根目录。
  • cwd: 指定调试器的当前工作目录。
  • 该 launch.json 配置文件定义了一个名为 "Launch Program" 的调试配置,用于使用 + ts-node 调试位于 src/main.ts 的 TypeScript 程序。配置包括跳过 Node.js 内部模块的文+ 件、预加载 tsconfig-paths/register 模块以支持路径映射,并在当前工作区目录下运行调试器。

3.实现基本服务

3.1 core\index.ts

core\index.ts

js
export * from './logger';
export * from './nest-application';
export * from './nest-factory';

3.2 logger.ts

src@nestjs\core\logger.ts

js
// 从 'cli-color' 模块中导入 clc,用于在终端中输出彩色文字
import clc from 'cli-color';
// 定义一个名为 Logger 的类
class Logger {
  // 定义一个静态方法 log,该方法接收两个参数:message 和 context
  static log(message: string, context: string = '') {
    // 获取当前日期和时间,并格式化为本地字符串
    const timestamp = new Date().toLocaleString();
    // 获取当前进程的 PID(进程标识符)
    const pid = process.pid;
    // 使用 console.log 输出格式化的日志信息
    console.log(
      `${clc.green('[Nest]')} ${clc.green(pid.toString())}  ${clc.green('-')} ${clc.yellow(timestamp)}     ${clc.green('LOG')} ${clc.yellow(`[${context}]`)} ${clc.green(message)}`
    );
  }
}
// 导出 Logger 类,以便其他模块可以使用
export { Logger };
```js
### 3.3 nest-factory.ts
src\@nestjs\core\nest-factory.ts
```js
import { Logger } from './logger';
// 引入 Logger 模块
import { NestApplication } from './nest-application';
// 引入 NestApplication 模块
export class NestFactory {
// 导出 NestFactory 类
  static async create<T>(module: any): Promise<NestApplication> {
  // 定义一个静态的异步方法 create,接收一个参数 module,返回一个 Promise,Promise 的类型是 NestApplication
    Logger.log('Starting Nest application...', 'NestFactory');
    // 使用 Logger 记录一条信息,表示正在启动 Nest 应用
    const app = new NestApplication(module);
    // 创建一个新的 NestApplication 实例,传入 module 参数
    return app;
    // 返回创建的 NestApplication 实例
  }
}

3.4 nest-application.ts

src@nestjs\core\nest-application.ts

js
// 导入 express 模块及相关类型
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
// 导入 path 模块
import path from 'path';
// 导入自定义的 Logger 模块
import { Logger } from './logger';

// 定义 NestApplication 类
class NestApplication {
  // 定义一个私有的 express 应用实例
  private readonly app: Express = express();
  // 定义一个私有的模块变量
  private readonly module: any;

  // 构造函数,接收一个模块参数
  constructor(module: any) {
    this.module = module;
  }
  // 定义 use 方法,用于注册中间件
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }
  // 定义 init 方法,初始化应用
  async init() {
    // 获取模块中的控制器元数据
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    // 记录日志:应用模块依赖已初始化
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');
    // 遍历所有控制器
    for (const Controller of controllers) {
      // 创建控制器实例
      const controller = new Controller();
      // 获取控制器的路由前缀元数据,默认为 '/'
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      // 获取控制器的原型对象
      const controllerPrototype = Reflect.getPrototypeOf(controller);
      // 记录日志:映射控制器名称和前缀
      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');
      // 遍历控制器原型对象上的所有方法
      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        // 获取方法的路径元数据
        const pathMetadata = Reflect.getMetadata('path', method);
        // 获取方法的 HTTP 方法元数据
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          // 组合路由路径
          const routPath = path.posix.join('/', prefix, pathMetadata);
          // 注册路由及其处理函数
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const result = await method.call(controller);
            res.send(result);
          });
          // 记录日志:映射路由路径和 HTTP 方法
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    // 记录日志:Nest 应用程序成功启动
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  // 定义 listen 方法,监听指定端口
  async listen(port: number) {
    // 初始化应用
    await this.init();
    // 监听指定端口
    this.app.listen(port, () => {
      // 记录日志:应用正在运行
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
// 导出 NestApplication 类
export { NestApplication };

3.5 common\index.ts

src@nestjs\common\index.ts

js
export * from './controller.decorator';
export * from './http-methods.decorator';
export * from './module.decorator';

3.6 controller.decorator.ts

common\controller.decorator.ts

js
// 导入 reflect-metadata 库
import 'reflect-metadata';
// 定义 ControllerOptions 接口,包含一个可选的 prefix 属性
interface ControllerOptions {
  prefix?: string;
}
// 定义 Controller 装饰器函数,可以没有参数
function Controller(): ClassDecorator;
// 定义 Controller 装饰器函数,可以接受一个字符串类型的 prefix 参数
function Controller(prefix: string): ClassDecorator;
// 定义 Controller 装饰器函数,可以接受一个 ControllerOptions 类型的 options 参数
function Controller(options: ControllerOptions): ClassDecorator;
// 定义 Controller 装饰器函数,可以接受一个字符串或 ControllerOptions 类型的参数
function Controller(prefixOrOptions?: string | ControllerOptions): ClassDecorator {
  // 初始化一个空的 options 对象
  let options: ControllerOptions = {};
  // 如果 prefixOrOptions 是字符串类型,则将其赋值给 options.prefix
  if (typeof prefixOrOptions === 'string') {
    options.prefix = prefixOrOptions;
  // 如果 prefixOrOptions 是对象类型,则将其赋值给 options
  } else if (typeof prefixOrOptions === 'object') {
    options = prefixOrOptions;
  }
  // 返回一个类装饰器函数,使用 Reflect.defineMetadata 将 prefix 元数据定义在目标类上
  return (target: Function) => {
    Reflect.defineMetadata('prefix', options.prefix || '', target);
  };
}
// 导出 Controller 装饰器函数
export { Controller };

3.7 http-methods.decorator.ts

src@nestjs\common\http-methods.decorator.ts

js
// 引入 reflect-metadata 库,该库用于在 TypeScript 中添加元数据
import 'reflect-metadata';
// 定义一个名为 Get 的函数,该函数接受一个字符串参数 path,默认值为空字符串
// Get 函数返回一个方法装饰器 MethodDecorator
export function Get(path: string = ''): MethodDecorator {
  // 返回一个方法装饰器,该装饰器接受三个参数:目标对象、属性键和属性描述符
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    // 使用 Reflect.defineMetadata 函数为属性描述符的值(即方法)定义 'path' 元数据
    Reflect.defineMetadata('path', path, descriptor.value);
    // 使用 Reflect.defineMetadata 函数为属性描述符的值(即方法)定义 'method' 元数据,值为 'GET'
    Reflect.defineMetadata('method', 'GET', descriptor.value);
  };
}

3.8 module.decorator.ts

src@nestjs\common\module.decorator.ts

js
// 引入 reflect-metadata 库,用于处理元数据
import 'reflect-metadata';
// 定义 ModuleMetadata 接口,包含一个可选的 controllers 属性,类型为 Function 数组
export interface ModuleMetadata {
  controllers?: Function[];
}
// 定义 Module 函数,接收一个 ModuleMetadata 类型的参数 metadata,返回一个 ClassDecorator
export function Module(metadata: ModuleMetadata): ClassDecorator {
  // 返回一个装饰器函数,接收一个目标函数(类)
  return (target: Function) => {
    // 使用 Reflect.defineMetadata 方法将 metadata.controllers 元数据定义到目标函数上,键为 'controllers'
    Reflect.defineMetadata('controllers', metadata.controllers, target);
  };
}

4.请求对象

4.1 app.module.ts

src\app.module.ts

js
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
+import { UserController } from './user.controller';
@Module({
+ controllers: [AppController,UserController],
})
export class AppModule {}

4.2 user.controller.ts

src\user.controller.ts

js
// 从 '@nestjs/common' 模块导入 Controller、Get、Request 和 Req 装饰器
import { Controller, Get, Request, Req } from '@nestjs/common';
// 从 'express' 模块导入 Request 类型并重命名为 ExpressRequest
import { Request as ExpressRequest } from 'express';
// 使用 @Controller 装饰器定义 'users' 路由
@Controller('users')
export class UserController {
  // 使用 @Get 装饰器定义根路径的 GET 请求处理函数
  @Get()
  findAllUsers(): string {
    // 返回一个字符串,表示此操作返回所有用户
    return 'This action returns all users';
  }
  // 使用 @Get 装饰器定义 '/info' 路径的 GET 请求处理函数
  @Get('info')
  getUserInfo(): string {
    // 返回一个字符串,表示此操作返回用户信息
    return 'This action returns the info of user';
  }
  // 使用 @Get 装饰器定义 '/req' 路径的 GET 请求处理函数
  @Get('req')
  // 处理请求的函数,使用 @Request 和 @Req 装饰器注入 ExpressRequest 对象
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    // 输出请求的 URL
    console.log(req.url);
    // 输出请求的路径
    console.log(req.path);
    // 输出请求的方法
    console.log(req.method);
    // 返回一个字符串,表示请求已处理
    return 'Request handled';
  }
}

4.3 common\index.ts

src@nestjs\common\index.ts

js
export * from './controller.decorator';
export * from './http-methods.decorator';
export * from './module.decorator';
+export * from './param-decorators';

4.4 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
// 引入 'reflect-metadata' 库,用于元数据的反射操作
import 'reflect-metadata';
// 定义一个工厂函数 createParamDecorator,用于创建参数装饰器
export const createParamDecorator = (key: string) => {
  // 返回一个装饰器函数,该函数接受可选的 data 参数
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    // 获取已经存在的参数元数据,如果不存在则初始化为空数组
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    // 将当前参数的信息(index, key, data)添加到参数元数据中
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    // 更新参数元数据到目标对象的属性上
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
// 使用 createParamDecorator 创建 'Request' 参数装饰器
export const Request = createParamDecorator('Request');
// 使用 createParamDecorator 创建 'Req' 参数装饰器
export const Req = createParamDecorator('Req');

4.5 nest-application.ts

src@nestjs\core\nest-application.ts

js
// 引入 express 及其相关类型
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
// 引入 path 模块
import path from 'path';
// 引入 Logger 类
import { Logger } from './logger';
// 定义 NestApplication 类
class NestApplication {
  // 定义私有的 express 实例
  private readonly app: Express = express();
  // 定义私有的模块属性
  private readonly module: any;
  // 构造函数,接收一个模块作为参数
  constructor(module: any) {
    this.module = module;
  }
  // 使用中间件的方法
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }
  // 初始化方法
  async init() {
    // 获取模块中定义的控制器
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    // 记录初始化日志
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');
    // 遍历所有控制器
    for (const Controller of controllers) {
      // 创建控制器实例
      const controller = new Controller();
      // 获取控制器的前缀
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      // 获取控制器的原型
      const controllerPrototype = Reflect.getPrototypeOf(controller);
      // 记录路由解析日志
      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');
      // 遍历控制器的方法
      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        // 获取方法的路径元数据
        const pathMetadata = Reflect.getMetadata('path', method);
        // 获取方法的 HTTP 方法元数据
        const httpMethod = Reflect.getMetadata('method', method);
        // 如果定义了 HTTP 方法
        if (httpMethod) {
          // 生成路由路径
          const routPath = path.posix.join('/', prefix, pathMetadata);
          // 定义路由
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
+           // 解析方法参数
+           const args = this.resolveParams(controller, methodName, req, res, next);
+           // 调用方法并获取结果
+           const result = await method.call(controller, ...args);
            // 发送响应结果
            res.send(result);
          });
          // 记录路由映射日志
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    // 记录应用启动成功日志
    Logger.log('Nest application successfully started', 'NestApplication');
  }
+ // 解析方法参数
+ private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
+   // 获取参数元数据
+   const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
+   // 根据参数的索引排序并返回参数数组
+   return paramsMetadata.map((param: any) => {
+     const {key} = param;
+     switch (key) {
+       case 'Request':
+       case 'Req':
+         return req;
+       default:
+         return null;
+     }
+   });
+ }
  // 启动监听方法
  async listen(port: number) {
    // 初始化应用
    await this.init();
    // 启动监听指定端口
    this.app.listen(port, () => {
      // 记录应用运行日志
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
// 导出 NestApplication 类
export { NestApplication };

5.Query

5.1 user.controller.ts

src\user.controller.ts

js
import { Controller, Get, Request, Req,Query} from '@nestjs/common';
import { Request as ExpressRequest} from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
+ @Get('query')
+ handleQuery(@Query() query:any,@Query('id') id: string): string {
+   console.log('query',query);
+   console.log('id',id);
+   return `Query ID: ${id}`;
+ }
}

5.2 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
import 'reflect-metadata';
export const createParamDecorator = (key: string) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
+export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);

5.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {index,key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
+       case 'Query':
+         return data?req.query[data]:req.query;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

6.获取请求头

6.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers} from '@nestjs/common';
import { Request as ExpressRequest} from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
+ @Get('headers')
+ handleHeaders(@Headers('accept') accept: string): string {
+   console.log(accept);
+   return `Header accept: ${accept}`;
+ }
}
6.2 param-decorators.ts
src\@nestjs\common\param-decorators.ts

import 'reflect-metadata';
export const createParamDecorator = (key: string) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);
+export const Headers = (headerKey?: string) => createParamDecorator(`Headers`)(headerKey);
6.3 nest-application.ts
src\@nestjs\core\nest-application.ts

import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {index,key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
+       case 'Headers':
+         return data?req.headers[data]:req.headers;   
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

7.获取会话

7.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session} from '@nestjs/common';
import { Request as ExpressRequest} from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
+ @Get('session')
+ handleSession(@Session() session: any): string {
+   if (session.views) {
+     session.views++;
+   } else {
+     session.views = 1;
+   }
+   return `Number of views: ${session.views}`;
+ }
}

7.2 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
import 'reflect-metadata';
export const createParamDecorator = (key: string) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};

export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);
export const Headers = (headerKey?: string) => createParamDecorator(`Headers`)(headerKey);
+export const Session = createParamDecorator('Session');

7.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {index,key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
+       case 'Session':
+         return req.session;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

8.IP

8.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session, Ip} from '@nestjs/common';
import { Request as ExpressRequest} from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
+ @Get('ip')
+ getUserIp(@Ip() ip: string): string {
+   console.log(ip);
+   return `IP: ${ip}`;
+ }
}

8.2 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
import 'reflect-metadata';
export const createParamDecorator = (key: string) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);
export const Headers = (headerKey?: string) => createParamDecorator(`Headers`)(headerKey);
export const Session = createParamDecorator('Session');
+export const Ip = createParamDecorator('Ip');

8.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {index,key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
+       case 'Ip':
+         return req.ip;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

9.路径参数

9.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param} from '@nestjs/common';
import { Request as ExpressRequest} from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
+ @Get('param/:id')
+ getParamById(@Param('id') id: string): string {
+   console.log('ID:', id);
+   return `Param ID: ${id}`;
+ }
}

9.2 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
import 'reflect-metadata';
export const createParamDecorator = (key: string) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);
export const Headers = (headerKey?: string) => createParamDecorator(`Headers`)(headerKey);
export const Session = createParamDecorator('Session');
export const Ip = createParamDecorator('Ip');
+export const Param = (paramKey?: string) => createParamDecorator(`Param`)(paramKey);

9.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {index,key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
        case 'Ip':
          return req.ip;
+       case 'Param':
+         return data?req.params[data]:req.params;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

10.路由通配符

基于模式的路由也是支持的。例如,星号用作通配符,将匹配任何字符组合。

10.1 user.controller.ts

src\user.controller.ts

js
import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param} from '@nestjs/common';
import { Request as ExpressRequest} from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
+ @Get('ab*de')
+ handleWildcardRoute() {
+   return 'This route uses a wildcard';
+ }
}

11.Post

11.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param, Post} from '@nestjs/common';
import { Request as ExpressRequest} from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
  @Get('ab*de')
  handleWildcardRoute() {
    return 'This route uses a wildcard';
  }
+ @Post('create')
+ createUser(): string {
+   return 'This action adds a new user';
+ }
}

11.2 http-methods.decorator.ts

src@nestjs\common\http-methods.decorator.ts

js
import 'reflect-metadata';
export function Get(path: string = ''): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('path', path, descriptor.value);
    Reflect.defineMetadata('method', 'GET', descriptor.value);
  };
}
+export function Post(path: string = ''): MethodDecorator {
+  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
+    Reflect.defineMetadata('path', path, descriptor.value);
+    Reflect.defineMetadata('method', 'POST', descriptor.value);
+  };
+}

12.请求体

12.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param, Post, Body} from '@nestjs/common';
import { Request as ExpressRequest} from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
  @Get('ab*de')
  handleWildcardRoute() {
    return 'This route uses a wildcard';
  }
  @Post('create')
+ createUser(@Body() createUserDto,@Body('username') username): string {
+   console.log('createUserDto',createUserDto);
+   console.log('username',username);
    return 'This action adds a new user';
  }
}

12.2 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
import 'reflect-metadata';
export const createParamDecorator = (key: string) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);
export const Headers = (headerKey?: string) => createParamDecorator(`Headers`)(headerKey);
export const Session = createParamDecorator('Session');
export const Ip = createParamDecorator('Ip');
export const Param = (paramKey?: string) => createParamDecorator(`Param`)(paramKey);
+export const Body = (bodyKey?: string) => createParamDecorator(`Body`)(bodyKey);

12.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
+   this.app.use(express.json());
+   this.app.use(express.urlencoded({ extended: true }));
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
        case 'Ip':
          return req.ip;
        case 'Param':
          return data?req.params[data]:req.params;
+       case 'Body':
+         return data?req.body[data]:req.body;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

13.响应

13.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param, Post, Body, Res, Response} from '@nestjs/common';
+import { Request as ExpressRequest, Response as ExpressResponse } from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
  @Get('ab*de')
  handleWildcardRoute() {
    return 'This route uses a wildcard';
  }
  @Post('create')
  createUser(@Body() createUserDto,@Body('username') username): string {
    console.log('createUserDto',createUserDto);
    console.log('username',username);
    return 'This action adds a new user';
  }
+ @Get('res')
+ handleResponse(@Res() res: ExpressResponse, @Response() response: ExpressResponse): void {
+   res.send('Custom response');
+ }
}

13.2 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
import 'reflect-metadata';
export const createParamDecorator = (key: string) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);
export const Headers = (headerKey?: string) => createParamDecorator(`Headers`)(headerKey);
export const Session = createParamDecorator('Session');
export const Ip = createParamDecorator('Ip');
export const Param = (paramKey?: string) => createParamDecorator(`Param`)(paramKey);
export const Body = (bodyKey?: string) => createParamDecorator(`Body`)(bodyKey);
+export const Res = createParamDecorator('Res');
+export const Response = createParamDecorator('Response');

13.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
+           const responseMeta = this.getResponseMetadata(controller, methodName);
+           if(!responseMeta) return res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
+ private getResponseMetadata(instance: any, methodName: string): any {
+   const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
+   return return paramsMetadata.filter(Boolean).find((param: any) => param.key === 'Res' || param.key === 'Response');
+ }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
        case 'Ip':
          return req.ip;
        case 'Param':
          return data?req.params[data]:req.params;
        case 'Body':
          return data?req.body[data]:req.body;
+       case 'Res':
+       case 'Response':
+         return res;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}

export { NestApplication };

14.passthrough

14.1 user.controller.ts

src\user.controller.ts

js
import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param, Post, Body, Res, Response} from '@nestjs/common';
import { Request as ExpressRequest, Response as ExpressResponse } from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
  @Get('ab*de')
  handleWildcardRoute() {
    return 'This route uses a wildcard';
  }
  @Post('create')
  createUser(@Body() createUserDto,@Body('username') username): string {
    console.log('createUserDto',createUserDto);
    console.log('username',username);
    return 'This action adds a new user';
  }
  @Get('res')
  handleResponse(@Res() res: ExpressResponse, @Response() response: ExpressResponse): void {
    res.send('Custom response');
  }
+ @Get('passthrough')
+ passthrough(@Res({passthrough:true}) res: ExpressResponse): string {
+   return 'Custom response';
+ }
}

14.2 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
import 'reflect-metadata';
export const createParamDecorator = (key: string) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
    existingParameters[parameterIndex]={ index: parameterIndex, key, data };
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);
export const Headers = (headerKey?: string) => createParamDecorator(`Headers`)(headerKey);
export const Session = createParamDecorator('Session');
export const Ip = createParamDecorator('Ip');
export const Param = (paramKey?: string) => createParamDecorator(`Param`)(paramKey);
export const Body = (bodyKey?: string) => createParamDecorator(`Body`)(bodyKey);
+export const Res = (options?:any) => createParamDecorator(`Res`)(options);
+export const Response =(options?:any) => createParamDecorator(`Response`)(options);

14.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            const responseMeta = this.getResponseMetadata(controller, methodName);
+           if(!responseMeta ||(responseMeta.data?.passthrough)) return res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private getResponseMetadata(instance: any, methodName: string): any {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return return paramsMetadata.filter(Boolean).find((param: any) => param.key === 'Res' || param.key === 'Response');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
        case 'Ip':
          return req.ip;
        case 'Param':
          return data?req.params[data]:req.params;
        case 'Body':
          return data?req.body[data]:req.body;
        case 'Res':
        case 'Response':
          return res;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

15.Redirect

15.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param, Post, Body, Res, Response,Redirect} from '@nestjs/common';
import { Request as ExpressRequest, Response as ExpressResponse } from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
  @Get('ab*de')
  handleWildcardRoute() {
    return 'This route uses a wildcard';
  }
  @Post('create')
  createUser(@Body() createUserDto,@Body('username') username): string {
    console.log('createUserDto',createUserDto);
    console.log('username',username);
    return 'This action adds a new user';
  }
  @Get('res')
  handleResponse(@Res() res: ExpressResponse, @Response() response: ExpressResponse): void {
    res.send('Custom response');
  }
  @Get('passthrough')
  passthrough(@Res({passthrough:true}) res: ExpressResponse): string {
    return 'Custom response';
  }
+  @Get('/redirect')
+  @Redirect('/users', 301)
+  handleRedirect(): void {}

+  @Get('redirect2')
+  @Redirect('/users', 302)
+  handleRedirect2() {
+    return { url: 'https://www.baidu.com',statusCode: 301};
+  }
}

15.2 ttp-methods.decorator.ts

src@nestjs\common\http-methods.decorator.ts

js
import 'reflect-metadata';

export function Get(path: string = ''): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('path', path, descriptor.value);
    Reflect.defineMetadata('method', 'GET', descriptor.value);
  };
}
export function Post(path: string = ''): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('path', path, descriptor.value);
    Reflect.defineMetadata('method', 'POST', descriptor.value);
  };
}
+export function Redirect(url: string = '/', statusCode: number = 302): MethodDecorator {
+  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
+    Reflect.defineMetadata('redirectUrl', url, descriptor.value);
+    Reflect.defineMetadata('redirectStatusCode', statusCode, descriptor.value);
+  };
+}

15.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
+       const redirectUrl = Reflect.getMetadata('redirectUrl', method);
+       const redirectStatusCode = Reflect.getMetadata('redirectStatusCode', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
+           if (result && result.url) {
+             res.redirect(result.statusCode || 302, result.url);
+             return;
+           }
+           if (redirectUrl) {
+             res.redirect(redirectStatusCode || 302, redirectUrl);
+             return;
+           }
            const responseMeta = this.getResponseMetadata(controller, methodName);
            if(!responseMeta ||(responseMeta.data?.passthrough)) return res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private getResponseMetadata(instance: any, methodName: string): any {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return return paramsMetadata.filter(Boolean).find((param: any) => param.key === 'Res' || param.key === 'Response');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
        case 'Ip':
          return req.ip;
        case 'Param':
          return data?req.params[data]:req.params;
        case 'Body':
          return data?req.body[data]:req.body;
        case 'Res':
        case 'Response':
          return res;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

16.HttpCode

16.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param, Post, Body, Res, Response,Redirect,HttpCode} from '@nestjs/common';
import { Request as ExpressRequest, Response as ExpressResponse } from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
  @Get('ab*de')
  handleWildcardRoute() {
    return 'This route uses a wildcard';
  }
  @Post('create')
+ @HttpCode(200)
  createUser(@Body() createUserDto,@Body('username') username): string {
    console.log('createUserDto',createUserDto);
    console.log('username',username);
    return 'This action adds a new user';
  }
  @Get('res')
  handleResponse(@Res() res: ExpressResponse, @Response() response: ExpressResponse): void {
    res.send('Custom response');
  }
  @Get('passthrough')
  passthrough(@Res({passthrough:true}) res: ExpressResponse): string {
    return 'Custom response';
  }
  @Get('/redirect')
  @Redirect('/users', 301)
  handleRedirect(): void {}

  @Get('redirect2')
  @Redirect('/users', 302)
  handleRedirect2() {
    return { url: 'https://www.baidu.com',statusCode: 301};
  }
}

16.2 http-methods.decorator.ts

src@nestjs\common\http-methods.decorator.ts

js
import 'reflect-metadata';

export function Get(path: string = ''): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('path', path, descriptor.value);
    Reflect.defineMetadata('method', 'GET', descriptor.value);
  };
}
export function Post(path: string = ''): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('path', path, descriptor.value);
    Reflect.defineMetadata('method', 'POST', descriptor.value);
  };
}
export function Redirect(url: string = '/', statusCode: number = 302): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('redirectUrl', url, descriptor.value);
    Reflect.defineMetadata('redirectStatusCode', statusCode, descriptor.value);
  };
}
+export function HttpCode(statusCode: number): MethodDecorator {
+  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
+    Reflect.defineMetadata('httpCode', statusCode, descriptor.value);
+  };
+}

16.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        const redirectUrl = Reflect.getMetadata('redirectUrl', method);
        const redirectStatusCode = Reflect.getMetadata('redirectStatusCode', method);
+       const httpCode = Reflect.getMetadata('httpCode', method);
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            if (result && result.url) {
              res.redirect(result.statusCode || 302, result.url);
              return;
            }
            if (redirectUrl) {
              res.redirect(redirectStatusCode || 302, redirectUrl);
              return;
            }
+           if (httpCode) {
+             res.status(httpCode);
+           } else if (httpMethod === 'POST') {
+             res.status(201);
+           }
            const responseMeta = this.getResponseMetadata(controller, methodName);
            if(!responseMeta ||(responseMeta.data?.passthrough)) return res.send(result);
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private getResponseMetadata(instance: any, methodName: string): any {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return return paramsMetadata.filter(Boolean).find((param: any) => param.key === 'Res' || param.key === 'Response');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
        case 'Ip':
          return req.ip;
        case 'Param':
          return data?req.params[data]:req.params;
        case 'Body':
          return data?req.body[data]:req.body;
        case 'Res':
        case 'Response':
          return res;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}

export { NestApplication };

17.响应头

17.1 user.controller.ts

src\user.controller.ts

js
+import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param, Post, Body, Res, Response,Redirect,HttpCode,Header} from '@nestjs/common';
import { Request as ExpressRequest, Response as ExpressResponse } from 'express';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
  @Get('ab*de')
  handleWildcardRoute() {
    return 'This route uses a wildcard';
  }
  @Post('create')
  @HttpCode(200)
+ @Header('Cache-Control', 'none')
  createUser(@Body() createUserDto,@Body('username') username): string {
    console.log('createUserDto',createUserDto);
    console.log('username',username);
    return 'This action adds a new user';
  }
  @Get('res')
  handleResponse(@Res() res: ExpressResponse, @Response() response: ExpressResponse): void {
    res.send('Custom response');
  }
  @Get('passthrough')
  passthrough(@Res({passthrough:true}) res: ExpressResponse): string {
    return 'Custom response';
  }
  @Get('/redirect')
  @Redirect('/users', 301)
  handleRedirect(): void {}

  @Get('redirect2')
  @Redirect('/users', 302)
  handleRedirect2() {
    return { url: 'https://www.baidu.com',statusCode: 301};
  }
}

17.2 http-methods.decorator.ts

src@nestjs\common\http-methods.decorator.ts

js
import 'reflect-metadata';

export function Get(path: string = ''): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('path', path, descriptor.value);
    Reflect.defineMetadata('method', 'GET', descriptor.value);
  };
}
export function Post(path: string = ''): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('path', path, descriptor.value);
    Reflect.defineMetadata('method', 'POST', descriptor.value);
  };
}
export function Redirect(url: string = '/', statusCode: number = 302): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('redirectUrl', url, descriptor.value);
    Reflect.defineMetadata('redirectStatusCode', statusCode, descriptor.value);
  };
}
export function HttpCode(statusCode: number): MethodDecorator {
  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
    Reflect.defineMetadata('httpCode', statusCode, descriptor.value);
  };
}
+export function Header(name: string, value: string): MethodDecorator {
+  return (target, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
+    const existingHeaders = Reflect.getMetadata('headers', descriptor.value) || [];
+    existingHeaders.push({ name, value });
+    Reflect.defineMetadata('headers', existingHeaders, descriptor.value);
+  };
+}

17.3 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        const redirectUrl = Reflect.getMetadata('redirectUrl', method);
        const redirectStatusCode = Reflect.getMetadata('redirectStatusCode', method);
        const httpCode = Reflect.getMetadata('httpCode', method);
+       const headers = Reflect.getMetadata('headers', method) || [];
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            if (result && result.url) {
              res.redirect(result.statusCode || 302, result.url);
              return;
            }
            if (redirectUrl) {
              res.redirect(redirectStatusCode || 302, redirectUrl);
              return;
            }
            if (httpCode) {
              res.status(httpCode);
            } else if (httpMethod === 'POST') {
              res.status(201);
            }
            const responseMeta = this.getResponseMetadata(controller, methodName);
            if(!responseMeta ||(responseMeta.data?.passthrough)){
+             headers.forEach((header: { name: string; value: string }) => {
+               res.setHeader(header.name, header.value);
+             });
              return res.send(result);
            } 
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private getResponseMetadata(instance: any, methodName: string): any {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return return paramsMetadata.filter(Boolean).find((param: any) => param.key === 'Res' || param.key === 'Response');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params:${methodName}`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {key,data} = param;
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
        case 'Ip':
          return req.ip;
        case 'Param':
          return data?req.params[data]:req.params;
        case 'Body':
          return data?req.body[data]:req.body;
        case 'Res':
        case 'Response':
          return res;
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}

export { NestApplication };

18.自定义参数装饰器

18.1 user.controller.ts

src\user.controller.ts

js
import { Controller, Get, Request, Req, Query, Headers, Session, Ip, Param, Post, Body, Res, Response,Redirect,HttpCode,Header} from '@nestjs/common';
import { Request as ExpressRequest, Response as ExpressResponse } from 'express';
import { UrlDecorator } from './url-decorator';
@Controller('users')
export class UserController {
  @Get()
  findAllUsers(): string {
    return 'This action returns all users';
  }
  @Get('info')
  getUserInfo(): string {
    return 'This action returns the info of user';
  }
  @Get('req')
  handleRequest(@Request() request: ExpressRequest, @Req() req: ExpressRequest): string {
    //console.log(request);
    //console.log(req);
    console.log(req.url);
    console.log(req.path);
    console.log(req.method);
    return 'Request handled';
  }
  @Get('query')
  handleQuery(@Query() query:any,@Query('id') id: string): string {
    console.log('query',query);
    console.log('id',id);
    return `Query ID: ${id}`;
  }
  @Get('headers')
  handleHeaders(@Headers('accept') accept: string): string {
    console.log(accept);
    return `Header accept: ${accept}`;
  }
  @Get('session')
  handleSession(@Session() session: any): string {
    if (session.views) {
      session.views++;
    } else {
      session.views = 1;
    }
    return `Number of views: ${session.views}`;
  }
  @Get('ip')
  getUserIp(@Ip() ip: string): string {
    console.log(ip);
    return `IP: ${ip}`;
  }
  @Get('param/:id')
  getParamById(@Param('id') id: string): string {
    console.log('ID:', id);
    return `Param ID: ${id}`;
  }
  @Get('ab*de')
  handleWildcardRoute() {
    return 'This route uses a wildcard';
  }
  @Post('create')
  @HttpCode(200)
  @Header('Cache-Control', 'none')
  createUser(@Body() createUserDto,@Body('username') username): string {
    console.log('createUserDto',createUserDto);
    console.log('username',username);
    return 'This action adds a new user';
  }
  @Get('res')
  handleResponse(@Res() res: ExpressResponse, @Response() response: ExpressResponse): void {
    res.send('Custom response');
  }
  @Get('passthrough')
  passthrough(@Res({passthrough:true}) res: ExpressResponse): string {
    return 'Custom response';
  }
  @Get('/redirect')
  @Redirect('/users', 301)
  handleRedirect(): void {}

  @Get('redirect2')
  @Redirect('/users', 302)
  handleRedirect2() {
    return { url: 'https://www.baidu.com',statusCode: 301};
  }
+ @Get('url')
+ urlMethod(@UrlDecorator('url') url: any) {
+   console.log('url',url);
+   return url;
+ }
}

18.2 url-decorator.ts

src\url-decorator.ts

js
import { createParamDecorator } from '@nestjs/common';
export const UrlDecorator = createParamDecorator(
  (data, ctx) => {
    const request = ctx.switchToHttp().getRequest();
    return request[data];
  },
);

18.3 param-decorators.ts

src@nestjs\common\param-decorators.ts

js
import 'reflect-metadata';
+export const createParamDecorator = (keyOrFactory: string|Function) => {
  return (data?: any) => (target: any, propertyKey: string | symbol, parameterIndex: number) => {
    const existingParameters = Reflect.getMetadata(`params`, target, propertyKey) || [];
+   if(keyOrFactory instanceof Function){
+     existingParameters[parameterIndex]={ index: parameterIndex,key:'DecoratorFactory',factory:keyOrFactory, data };
+   }else{
+     existingParameters[parameterIndex]={ index: parameterIndex, key:keyOrFactory, data };
+   }
    Reflect.defineMetadata(`params`, existingParameters, target, propertyKey);
  };
};
export const Request = createParamDecorator('Request');
export const Req = createParamDecorator('Req');
export const Query = (queryKey?: string) => createParamDecorator(`Query`)(queryKey);
export const Headers = (headerKey?: string) => createParamDecorator(`Headers`)(headerKey);
export const Session = createParamDecorator('Session');
export const Ip = createParamDecorator('Ip');
export const Param = (paramKey?: string) => createParamDecorator(`Param`)(paramKey);
export const Body = (bodyKey?: string) => createParamDecorator(`Body`)(bodyKey);
export const Res = (options?:any) => createParamDecorator(`Res`)(options);
export const Response =(options?:any) => createParamDecorator(`Response`)(options);

18.4 nest-application.ts

src@nestjs\core\nest-application.ts

js
import express, { Express, Request as ExpressRequest, Response as ExpressResponse, NextFunction } from 'express';
import path from 'path';
import { Logger } from './logger';

class NestApplication {
  private readonly app: Express = express();
  private readonly module: any;

  constructor(module: any) {
    this.module = module;
    this.app.use(express.json());
    this.app.use(express.urlencoded({ extended: true }));
  }
  use(middleware: (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => void) {
    this.app.use(middleware);
  }

  async init() {
    const controllers = Reflect.getMetadata('controllers', this.module) || [];
    Logger.log('AppModule dependencies initialized', 'InstanceLoader');

    for (const Controller of controllers) {
      const controller = new Controller();
      const prefix = Reflect.getMetadata('prefix', Controller) || '/';
      const controllerPrototype = Reflect.getPrototypeOf(controller);

      Logger.log(`${Controller.name} {${prefix}}:`, 'RoutesResolver');

      for (const methodName of Object.getOwnPropertyNames(controllerPrototype)) {
        const method = controllerPrototype[methodName];
        const pathMetadata = Reflect.getMetadata('path', method);
        const httpMethod = Reflect.getMetadata('method', method);
        const redirectUrl = Reflect.getMetadata('redirectUrl', method);
        const redirectStatusCode = Reflect.getMetadata('redirectStatusCode', method);
        const httpCode = Reflect.getMetadata('httpCode', method);
        const headers = Reflect.getMetadata('headers', method) || [];
        if (httpMethod) {
          const routPath = path.posix.join('/', prefix, pathMetadata);
          this.app[httpMethod.toLowerCase()](routPath, async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
            const args = this.resolveParams(controller, methodName, req, res, next);
            const result = await method.call(controller, ...args);
            if (result && result.url) {
              res.redirect(result.statusCode || 302, result.url);
              return;
            }
            if (redirectUrl) {
              res.redirect(redirectStatusCode || 302, redirectUrl);
              return;
            }
            if (httpCode) {
              res.status(httpCode);
            } else if (httpMethod === 'POST') {
              res.status(201);
            }
            const responseMeta = this.getResponseMetadata(controller, methodName);
            if(!responseMeta ||(responseMeta.data?.passthrough)){
              headers.forEach((header: { name: string; value: string }) => {
                res.setHeader(header.name, header.value);
              });
              return res.send(result);
            } 
          });
          Logger.log(`Mapped {${routPath}, ${httpMethod}} route`, 'RouterExplorer');
        }
      }
    }
    Logger.log('Nest application successfully started', 'NestApplication');
  }
  private getResponseMetadata(instance: any, methodName: string): any {
    const paramsMetadata = Reflect.getMetadata(`params`, instance, methodName) || [];
    return return paramsMetadata.filter(Boolean).find((param: any) => param.key === 'Res' || param.key === 'Response');
  }
  private resolveParams(instance: any, methodName: string, req: ExpressRequest, res: ExpressResponse, next: Function): any[] {
    const paramsMetadata = Reflect.getMetadata(`params`, instance, methodName) || [];
    return paramsMetadata.map((param: any) => {
      const {key,data} = param;
+     const ctx =             {
+       switchToHttp: () => ({
+         getRequest: () => req,
+         getResponse: () => res,
+         getNext: () => next,
+       }),
+     }
      switch (key) {
        case 'Request':
        case 'Req':
          return req;
        case 'Query':
          return data?req.query[data]:req.query;
        case 'Headers':
          return data?req.headers[data]:req.headers;
        case 'Session':
          return req.session;
        case 'Ip':
          return req.ip;
        case 'Param':
          return data?req.params[data]:req.params;
        case 'Body':
          return data?req.body[data]:req.body;
        case 'Res':
        case 'Response':
          return res;
+       case 'DecoratorFactory':
+         return param.factory(data,ctx);
        default:
          return null;
      }
    });
  }
  async listen(port: number) {
    await this.init();
    this.app.listen(port, () => {
      Logger.log(`Application is running on: http://localhost:${port}`, 'NestApplication');
    });
  }
}
export { NestApplication };

参考

1.next

  • express 中的 next 是用于中间件链处理的函数。每个中间件函数接收三个参数:req、res 和 next。中间件函数通过调用 next 将控制权传递给下一个中间件函数。如果中间件没有调用 next,请求将会挂起。

  • express 中 next 的工作原理

1.中间件定义:

中间件函数可以处理请求、响应对象,并决定是否将控制权传递给下一个中间件。 中间件可以修改请求和响应对象。

2.调用链:

express 会按顺序执行中间件。 每个中间件必须显式调用 next 函数,才能将控制权传递给下一个中间件。

3.错误处理:

如果 next 被调用时带有参数,那么 express 将跳过所有剩余的非错误处理中间件,直接传递给专门的错误处理中间件。

js
class Request {
    url:string;
    constructor(url) {
        this.url = url;
    }
}
class Response {
    send(message) {
        console.log(message);
    }
}
class SimpleExpress {
    middlewares:any[]
    constructor() {
        this.middlewares = [];
    }
    use(middleware) {
        this.middlewares.push(middleware);
    }
    handleRequest(req, res) {
        const chain = this.middlewares;
        let index = 0;
        const next = (err?) => {
            if (err) {
                console.error(err);
                return;
            }
            if (index < chain.length) {
                const middleware = chain[index++];
                middleware(req, res, next);
            }
        };
        next();
    }
}
const app = new SimpleExpress();
app.use((req, res, next) => {
    console.log(`Middleware 1: ${req.url}`);
    next();
});
app.use((req, res, next) => {
    console.log(`Middleware 2`);
    next();
});
app.use((req, res, next) => {
    console.log(`Middleware 3`);
    res.send('Hello from Middleware 3');
});
const req = new Request('/test');
const res = new Response();
app.handleRequest(req, res);
export { }
  • Request 和 Response 类: express 的 req 和 res 对象。
  • SimpleExpress 类: express 应用,包含中间件注册 (use) 和请求处理 (handleRequest) + 方法。
  • handleRequest 方法:执行中间件链,通过 next 函数传递控制权。
  • next 函数:递归调用下一个中间件。如果没有更多的中间件,则停止执行。