安装
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/common | NestJS的公共模块,包含各种装饰器、工具函数和中间件,用于构建NestJS应用程序的核心功能。 |
@nestjs/core | NestJS的核心模块,提供创建NestJS应用程序的基础设施,包括依赖注入、模块系统等。 |
express-session | 用于Express框架的会话中间件,支持会话数据的存储和管理。 |
reflect-metadata | 用于在TypeScript和JavaScript中实现反射的库,支持元数据的定义和读取。 |
rxjs | Reactive Extensions for JavaScript,提供基于Observable的响应式编程库。 |
nodemon | 一个Node.js工具,用于在检测到文件更改时自动重新启动应用程序。 |
ts-node | 一个TypeScript执行引擎,允许直接运行TypeScript代码而无需预先编译。 |
tsconfig-paths | 一个工具,用于解析TypeScript配置文件中的路径映射,支持模块路径的别名。 |
typescript | TypeScript编程语言的编译器,提供静态类型检查和最新的JavaScript特性。 |
2.启动项目
2.1 app.controller.ts
src\app.controller.ts
// 从 @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
// 从 @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
// 从 @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
{
"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
{
"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
{
"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
{
"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
export * from './logger';
export * from './nest-application';
export * from './nest-factory';
3.2 logger.ts
src@nestjs\core\logger.ts
// 从 '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
// 导入 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
export * from './controller.decorator';
export * from './http-methods.decorator';
export * from './module.decorator';
3.6 controller.decorator.ts
common\controller.decorator.ts
// 导入 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
// 引入 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
// 引入 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
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
// 从 '@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
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
// 引入 '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
// 引入 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
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
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
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
+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
+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
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
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
+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
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
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
+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
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
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
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
+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
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
+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
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
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
+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
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
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
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
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
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
+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
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
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
+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
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
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
+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
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
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
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
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
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
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 将跳过所有剩余的非错误处理中间件,直接传递给专门的错误处理中间件。
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 函数:递归调用下一个中间件。如果没有更多的中间件,则停止执行。