cnpm i @nestjs/mongoose mongoose --save
// mongo.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [MongooseModule.forRoot('mongodb://localhost/demo', { useNewUrlParser: true })],
})
export class MongoModule { }
// mongo.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [
MongooseModule.forRootAsync({
// 1. 异步加载,使用useFactory方法返回参数对象配置
useFactory: () => ({
uri: 'mongodb://localhost/demo',
useNewUrlParser: true,
}),
// 2.使用useClass配置,传递一个类,实现MongooseOptionsFactory接口,重写方法
// useClass: MongooseConfigService,
}),
})
export class MongoModule { }
// config.service.ts
import { Injectable } from '@nestjs/common';
import { MongooseOptionsFactory, MongooseModuleOptions } from '@nestjs/mongoose';
@Injectable()
export class MongooseConfigService implements MongooseOptionsFactory {
createMongooseOptions(): MongooseModuleOptions {
return {
uri: 'mongodb://localhost/demo',
useNewUrlParser: true,
};
}
}
import { MongooseConfigService } from './config.service';
引入使用// user/user.schema.ts
import { Schema } from 'mongoose';
// 创建一个文档架构
export const UserSchema = new Schema({
name: String,
password: String,
phone: String,
email: String,
times: Number,
});
// user/user.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UserSchema } from './user.schema';
/**
* 连接mongodb的用户模块,使用mongoose的模块并配置
*/
@Module({
imports: [MongooseModule.forFeature([{ name: 'users', schema: UserSchema }])],
})
export class UserModule { }
name:'users'
就是对应的mongodb的数据库里面的users集合,又因为forFeature接收的是一个数组,所以可以设置连接多个集合
// user/user.service.ts
import { Model } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { User } from './user.interface';
import { CreateUserDto } from './create-user.dto';
@Injectable()
export class UserService {
constructor(@InjectModel('users') private readonly userModel: Model<User>) {}
async create(createUserDto: CreateUserDto): Promise<User> {
const createdUser = new this.userModel(createUserDto); // 添加一个文档
return await createdUser.save();
}
async findAll(): Promise<User[]> { // 查询全部文档
return await this.userModel.find().exec();
}
}
@InjectModel('users')
中的users就是对应的集合 然后注入到对应的userModel中,之后就可以进行增删改查等import { User } from './user.interface';
import { CreateUserDto } from './create-user.dto';
// 这两个就是对应的接口和dto
// user/user.interface.ts
export interface User {
readonly name: string;
readonly password: string;
readonly phone: string;
readonly email: string;
readonly times: number;
}
// user/create-user.dto.ts
import { User } from './user.interface';
export class CreateUserDto implements User {
public readonly name: string;
public readonly phone: string;
public readonly email: string;
public readonly times: number;
public readonly password: string;
}
// user/user.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { User } from './user.interface';
import { UserService } from './user.service';
import { CreateUserDto } from './create-user.dto';
@Controller('/mongo')
export class UserController {
public constructor(private readonly userService: UserService) { }
@Get()
public getUsers(): Promise<User[]> {
return this.userService.findAll();
}
@Post()
public createUser(@Body() createUserDto: CreateUserDto): Promise<CreateUserDto> {
return this.userService.create(createUserDto);
}
}
cnpm i multer -S
import { Module } from '@nestjs/common';
import { MulterModule } from '@nestjs/platform-express';
/**
* 文件上传控制器
*/
@Module({
imports: [
MulterModule.register({
dest: './uploadFile', // 文件存储位置,项目根目录算起
// preservePath: ,// 保留路径
// fileFilter: , // 文件过滤器,函数,可以控制可上传的文件类型
// storage: , // 文件存储位置,特点是可以配置一个multer的diskStorage执行函数
// limits: , // 限制文件上传的大小
}),
],
})
export class UploadModule { }
import { Module } from '@nestjs/common';
import { MulterModule } from '@nestjs/platform-express';
import { MulterConfigService } from './multerConfig.service';
/**
* 文件上传控制器
*/
@Module({
imports: [
// 异步配置
MulterModule.registerAsync({
// 1. 直接useFactory配置
// useFactory: () => ({
// dest: './uploadFile',
// }),
// 服务配置
useClass: MulterConfigService,
}),
],
})
export class UploadModule { }
import { Injectable } from '@nestjs/common';
import { MulterOptionsFactory, MulterModuleOptions } from '@nestjs/platform-express';
import { Request } from 'express';
import { diskStorage } from 'multer';
/**
* 上传的文件配置服务
*/
@Injectable()
export class MulterConfigService implements MulterOptionsFactory {
createMulterOptions(): MulterModuleOptions {
return {
// dest: './uploadFile',
fileFilter(req: Request, file: any, cb: (error: Error, acceptFile: boolean) => void): void {
// 需要调用回调函数 `cb`,
// 并在第二个参数中传入一个布尔值,用于指示文件是否可接受
// 如果要拒绝文件,上传则传入 `false`。如:
// cb(null, false);
// 如果接受上传文件,则传入 `true`。如:
cb(null, true);
// 出错后,可以在第一个参数中传入一个错误:
// cb(new Error('I don\'t have a clue!'));
// console.log(file.filename);
// cb(null, false);
},
storage : diskStorage({
destination: (req, file, cb) => {
cb(null, './uploadFile');
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
}),
};
}
}
storge:比dest的好处是,可以配置一个multer的diskStorage,可以让上传的文件拥有文件名和文件后缀
destination:就是对应的文件路径
filename:就是对应的文件名和文件后缀的设置
import { Controller, Post, UseInterceptors, UploadedFile, UploadedFiles } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
/**
* 文件获取流
*/
@Controller('/upload')
export class UploadController {
/** 单个文件上传 */
@Post('/one')
// FileInterceptor()采用两个参数,一个fieldName(从保持一个文件的HTML表单指向场)和可选的options对象。这些MulterOptions等同于传递给multer构造函数
@UseInterceptors(FileInterceptor('file', { // FileInterceptor 第二个参数的storage 可以配置文件的保存文件名等
// storage: diskStorage({
// // destination: (req, file, cb) => {
// // cb(null, '/Users/liu/Desktop/test/');
// // },
// filename: (req, file, cb) => {
// cb(null, file.originalname);
// },
// }),
}))
public uploadFile(@UploadedFile() file: any): any {
console.log(file);
return file;
// return 'file 对应参数名的单个文件上传';
}
}
FileInterceptor:文件流拦截器,拦截单个文件,第一个参数是字符串,用于拦截的文件的参数名,第二个参数就是一个可配置项,可以配置和upload.module.ts里面的MulterModule.register里面的对象参数一致的参数
UploadedFile装饰器,则是接收拦截到的文件流,正常在有multer的配置下,拦截到的只是一个保存后的文件的信息对象
例如:{
"fieldname": "file",
"originalname": "a.jpg",
"encoding": "7bit",
"mimetype": "image/jpeg",
"destination": "./uploadFile",
"filename": "ajpg",
"path": "uploadFile/a.jpg",
"size": 11145
}
下面都是UploadedFiles
从@nestjs/common导出
@Post('/many')
// 为了上传文件数组,我们使用FilesInterceptor()。这个拦截器有三个参数。fieldName(保持不变),maxCount即可以同时上载的最大文件数,以及可选MulterOptions对象。
@UseInterceptors(FilesInterceptor('files', 10))
public uploadFileArray(@UploadedFiles() files: any): any {
// console.log(files);
return files;
}
FilesInterceptor
同样从@nestjs/platform-express导出
/** 不同参数名的多个文件 */
@Post('/manyFiles')
@UseInterceptors(FileFieldsInterceptor([
{ name: 'avatar', maxCount: 3 },
{ name: 'background', maxCount: 1 },
]))
public uploadFiles(@UploadedFiles() files: any): any {
// console.log(files);
// return 'files 不同参数名的多个文件';
return files;
}
name就是对应的参数名,maxCount就是这个参数名的最大的上传数
UseInterceptors
同样从@nestjs/platform-express导出
/**
* 任何文件
*/
@Post('/any')
@UseInterceptors(AnyFilesInterceptor())
public anyUploadFile(@UploadedFiles() files) {
// console.log(files);
// return 'files 任何文件';
return files;
}
cnpm i class-validator
app.useGlobalPipes(new ValidationPipe({
disableErrorMessages: true, // 错误消息对于理解通过网络发送的数据有什么问题有很大帮助。但是,在某些生产环境中,您可能希望禁用详细错误。
transform: true, // 该ValidationPipe不会自动将您的有效载荷到相应的DTO类。
})); // 全局验证
{
provide: APP_PIPE, // APP_PIPE 常量,可以自己配置
useClass: ValidationPipe,
},
最后,只要在dto中使用验证即可,验证不通过会自动返回对应的验证不通过的信息给前端,当disableErrorMessages设置为ture的话,就不返回对应的错误信息
缓存是一种非常简单的技术,有助于提高应用程序的性能。它充当临时数据存储,提供高性能数据访问。
cnpm i --save cache-manager
import { CacheModule, Module } from '@nestjs/common';
@Module({
imports: [CacheModule.register()],
})
export class CacheConfigModule { }
import { CacheInterceptor } from '@nestjs/common';
// @UseInterceptors(new CacheInterceptor(cacheManager,reflector)) // 使用缓存 接收两个参数,还未深究
// 在模块中使用
{
provide: APP_INTERCEPTOR,
useClass: CacheInterceptor,
},
Exclude 装饰器,被装饰后的属性会被排除
import { Exclude } from 'class-transformer';
export class UserEntity {
id: number;
firstName: string;
lastName: string;
@Exclude()
password: string;
constructor(partial: Partial<UserEntity>) {
Object.assign(this, partial);
}
}
Expose装饰器,装饰后的对应的get方法会成为一个参数一样被暴露出去
import { Expose } from 'class-transformer';
@Expose()
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
您可以使用@Transform()装饰器执行其他数据转换。例如,您要选择一个名称RoleEntity而不是返回整个对象。如下,暴露出name和age,不暴露其它的属性
@Transform(role => ({name:role.name,age:role.age}))
role: RoleEntity;
该@SerializeOptions()装饰器从进口@nestjs/common包。
@SerializeOptions({
// excludePrefixes: ['_'], // 排除前缀为_
})
@Get()
findOne(): UserEntity {
return {};
}
const app = await NestFactory.create(ApplicationModule, {
logger: ['error', 'warn'],
});
await app.listen(3000);
import { LoggerService } from '@nestjs/common';
export class MyLogger implements LoggerService {
log(message: string) {}
error(message: string, trace: string) {}
warn(message: string) {}
debug(message: string) {}
verbose(message: string) {}
}
// logger:['error', 'warn']
logger:new MyLogger()
// 只需扩展内置Logger类以部分覆盖默认实现,并使用super委托将调用委托给父类。
import { Logger } from '@nestjs/common';
export class MyLogger extends Logger {
error(message: string, trace: string) {
// add your tailored logic here
super.error(message, trace);
}
}
// 使用
// logger:new MyLogger()
app.useLogger(app.get(MyLogger)); // 解决方案的唯一缺点是您的第一个初始化消息将不会由您的记录器实例处理,但此时它并不重要。
cnpm i helmet csurf express-rate-limit -S
helmet:
保护您的应用免受一些众所周知的Web漏洞的影响。通常,Helmet只是12个较小的中间件函数的集合,它们设置与安全相关的HTTP头
csurf:
跨站点请求伪造(称为CSRF或XSRF)是一种恶意利用网站,其中未经授权的命令从Web应用程序信任的用户传输。要缓解此类攻击,您可以使用csurf软件包。
express-rate-limit :
防止过度请求的一个库,限制规定时间内的请求次数等
import * as helmet from 'helmet';
import * as csurf from 'csurf';
import * as rateLimit from 'express-rate-limit';
// 全局配置跨域
app.enableCors(); // 这个nest自带
// 通过适当地设置HTTP标头,头盔可以帮助保护您的应用免受一些众所周知的Web漏洞的影响。通常,Helmet只是12个较小的中间件函数的集合,它们设置与安全相关的HTTP头(阅读更多)。
app.use(helmet());
// 跨站点请求伪造(称为CSRF或XSRF)是一种恶意利用网站,其中未经授权的命令从Web应用程序信任的用户传输。要缓解此类攻击,您可以使用csurf软件包。
// app.use(csurf()); // 跨站点请求伪造,当前后端分离的项目,别乱使用
// 为了保护您的应用程序免受暴力攻击,您必须实现某种速率限制。幸运的是,NPM上已经有很多各种中间件可用。其中一个是快速限额。
app.use(
rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
}),
);
cnpm i --save compression
import * as compression from 'compression';
// somewhere in your initialization file
app.use(compression());
Fastify为Nest提供了一个很好的替代框架,因为它以类似于Express的方式解决了设计问题。然而,fastify 比Express 快得多,实现了几乎两倍的基准测试结果。
cnpm i --save @nestjs/platform-fastify
第二个参数变成了new FastifyAdapter(),这时候对应的对象配置直接传递给FastifyAdapter对象
// src/main.ts
import { NestFactory } from '@nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({ logger: false, })
);
await app.listen(3000);
}
bootstrap();
@Get()
index (@Res() res) {
// send 302 redirect to /login
res.status(302).redirect('/login');
}