官网:nestjs.com
中文官网: docs.nestjs.cn
Github: github.com/nestjs/nest
controller(控制器)
import { Controller, Get, Render, Post, Body,Response, Query } from '@nestjs/common';
import { RoleService } from "./../../../service/role/role.service";
import { Config } from "./../../../config/config";
import { ToolsService } from '../../../service/tools/tools.service';
@Controller(`${Config.adminPath}/role`)
export class RoleController {
constructor(private roleService:RoleService,private toolsService:ToolsService){}
@Get()
@Render('admin/role/index')
async index(){
let result = await this.roleService.find({});
return {
roleList:result
}
}
@Get('add')
@Render('admin/role/add')
async add(){
return {}
}
@Get('edit')
@Render('admin/role/edit')
async edit(@Query() query){
let result = await this.roleService.find({"_id":query.id})
return {
roleList:result[0]
}
}
@Post('doAdd')
async doAdd(@Body() body,@Response() res){
if (body.title != '') {
let result = await this.roleService.add(body);
if (result) {
this.toolsService.success(res,`/${Config.adminPath}/role`)
}else{
this.toolsService.error(res,'添加角色失败',`/${Config.adminPath}/role`)
}
}else{
this.toolsService.error(res,'标题不能为空',`/${Config.adminPath}/role`)
}
}
@Post('doEdit')
async doEdit(@Body() body,@Response() res){
if (body.title != '') {
let result = await this.roleService.update({"_id":body._id},body);
if (result) {
this.toolsService.success(res,`/${Config.adminPath}/role`)
}else{
this.toolsService.error(res,'修改角色失败',`/${Config.adminPath}/role`)
}
}else{
this.toolsService.error(res,'标题不能为空',`/${Config.adminPath}/role`)
}
}
@Get('delete')
async delete(@Query() query,@Response() res){
let result = await this.roleService.delete({"_id":query._id});
if (result) {
this.toolsService.success(res,`/${Config.adminPath}/role`)
}else{
this.toolsService.error(res,'删除角色失败',`/${Config.adminPath}/role`)
}
}
}
service(服务层)
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import {RoleInterface} from './../../interface/role.interface';
@Injectable()
export class RoleService {
constructor(@InjectModel('Role') private readonly roleModel){}
/**
* 查询
* @param json
* @param fields
*/
async find(json:RoleInterface,fields?:string){
try {
return await this.roleModel.find(json,fields);
} catch (error) {
return null;
}
}
/**
* 新增
* @param json
*/
async add(json:RoleInterface){
try {
const role = new this.roleModel(json)
return await role.save()
} catch (error) {
return null;
}
}
/**
* 更新
* @param orginJson
* @param newJson
*/
async update(orginJson:RoleInterface,newJson:RoleInterface){
try {
return await this.roleModel.updateOne(orginJson,newJson)
} catch (error) {
return null;
}
}
/**
* 删除
* @param json
*/
async delete(json:RoleInterface){
try {
return await this.roleModel.deleteOne(json)
} catch (error) {
return null;
}
}
}
module(模块)
app.module
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AdminModule } from './module/admin/admin.module';
import { DefaultModule } from './module/default/default.module';
import { ApiModule } from './module/api/api.module';
import { MongooseModule } from '@nestjs/mongoose';
import {Config} from './config/config';
//引入中间件
import { AdminauthMiddleware } from "./middleware/adminauth.middleware";
import { InitMiddleware } from "./middleware/init.middleware";
@Module({
imports: [AdminModule, DefaultModule, ApiModule,
MongooseModule.forRoot('mongodb://admin:123456@120.77.223.59:27017/millet?authSource=admin', { useNewUrlParser: true })],
controllers: [],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(AdminauthMiddleware)
.forRoutes(`${Config.adminPath}/*`)
.apply(InitMiddleware)
.forRoutes('*')
}
}
admin.module
import { Module } from '@nestjs/common';
import { MainController } from './main/main.controller';
import { LoginController } from './login/login.controller';
import { ManagerController } from './manager/manager.controller';
import {ToolsService} from './../../service/tools/tools.service';
import { MongooseModule } from '@nestjs/mongoose';
import { AdminSchema } from "./../../schema/admin.schema";
import { AdminService } from './../../service/admin/admin.service';
import { RoleSchema } from '../../schema/role.schema';
import {RoleService} from './../../service/role/role.service';
import { RoleController } from './role/role.controller';
@Module({
imports:[MongooseModule.forFeature([
{ name: 'Admin', schema: AdminSchema,collection:'admin' },
{ name:'Role',schema: RoleSchema,collection:'role'}
])],
controllers: [MainController, LoginController, ManagerController, RoleController],
providers:[ToolsService,AdminService,RoleService]
})
export class AdminModule {}
守卫
安装
nest g guard 文件夹/文件名
nest g guard guard/auth
基本使用
auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return validateRequest(request);
}
}
控制器类上使用
@Controller('cats')
@UseGuards(AuthGuard)
export class CatsController {
...
}
控制器方法上使用
@Get('guard')
@UseGuards(AuthGuard)
guard(@Query() info){
console.log(info);
return `this is guard`;
}
全局使用
main.ts
app.useGlobalGuards(new AuthGuard());
在守卫中获取Cookie和Session
main.ts
//配置cookie中间件
app.use(cookieParser("this signed cookies"))
//配置session中间件
app.use(session({secret:'keyboard cat',cookie:{maxAge:9000,httpOnly:true}}))
//配置全局守卫
app.useGlobalGuards(new AuthGuard());
login.controller.ts
@Controller('login')
@UseGuards(AuthGuard)
export class LoginController {
@Get()
index(@Request() req){
req.session.username = '张三';
return '登录成功'
}
}
auth.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext,): boolean | Promise<boolean> | Observable<boolean> {
let req = context.switchToHttp().getRequest()
if(req.path == 'admin/login'){
return true;
}else{
//context.switchToHttp().getRequest().cookies
let userinfo = context.switchToHttp().getRequest().session.username
if(userinfo){
return true;
}
return false;
}
}
}
第三方中间件
第三方包
cookie-parser(cookie)
npm install cookie-parser --save
//main.ts
import * as cookieParser from 'cookie-parser'
app.use(cookieParser)
#设置cookie
res.cookie("name",'zhangsan',{maxAge: 900000, httpOnly: true});
//HttpOnly 默认 false 不允许 客户端脚本访问
#获取cookie
@Get('getCookies')
getCookies(@Request() req){
return req.cookies.name;
}
#删除cookie
res.cookie('rememberme', '', { expires: new Date(0)});
设置cookie参数
domain: (String) 域名 expires:(Date) 过期时间(秒),在设置的某个时间点后该 Cookie 就会失效,如expires=Wednesday, 09-Nov-99 23:12:40 GMT maxAge:(String) 最大失效时间(毫秒),设置在多少后失效 secure:(Boolean) 当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效 path:(String) 表示 cookie 影响到的路,如 path=/。如果路径不能匹配时,浏览器则不发送这个 Cookie httpOnly:(Boolean) 是微软对 COOKIE 做的扩展。如果在 COOKIE 中设置了“httpOnly”属性,则通过程序(JS 脚本、applet 等)将无法读取到 COOKIE 信息,防止 XSS 攻击产生 signed:(Boolean) 表示是否签名 cookie, 设为 true 会对这个 cookie 签名,这样就需要用res.signedCookies 而不是 res.cookies 访问它。被篡改的签名 cookie 会被服务器拒绝,并且cookie 值会重置为它的原始值
Nestjs 中 Cookie 加密
- 配置中间件的时候需要传参
app.use(cookieParser('123456')); //相当于密钥
- 设置 cookie 的时候配置 signed 属性
res.cookie('userinfo','hahaha',{domain:'.ccc.com',maxAge:900000,httpOnly:true,signed:true});
- signedCookies 调用设置的 cookie
console.log(req.signedCookies);
express-session(session)
npm install express-session --save
import * as session from 'express-session';
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
#设置值
req.session.username = "张三";
#获取值
req.session.username
配置参数
app.use(session({
secret: '12345',
name: 'name',
cookie: {maxAge: 60000},
resave: false,
saveUninitialized: true
}));
| 参数 | 作用 |
|---|---|
| secret | 一个 String 类型的字符串,作为服务器端生成 session 的签名。 |
| name | 返回客户端的 key 的名称,默认为 connect.sid,也可以自己设置。 |
| resave | 强制保存 session 即使它并没有变化,。默认为 true。建议设置成 false。 don't save session if unmodifie |
| saveUninitialized | 强制将未初始化的 session 存储。当新建了一个 session 且未设定属性或值时,它就处于未初始化状态。在设定一个 cookie 前,这对于登陆验证,减轻服务端存储压力,权限控制是有帮助的。(默认:true)。建议手动添加。 |
| cookie | 设置返回到前端 key 的属性,默认值为{ path: ‘/’, httpOnly: true, secure: false, maxAge: null }。 |
| rolling | 在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false) |
常用方法
/*销毁 session*/
req.session.destroy(function(err) {})
req.session.username='张三'; //设置 session
req.session.username //获取 session
req.session.cookie.maxAge=0; //重新设置 cookie 的过期时间
模板引擎
ejs
npm install ejs --save
nunjucks
安装使用
npm install nunjucks -S
main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import {join} from 'path';
import * as nunjucks from 'nunjucks';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// app.useStaticAssets('public');
app.useStaticAssets(join(__dirname, '..', 'public'),{
prefix: '/static/', //设置虚拟路径
});
app.setBaseViewsDir(join(__dirname, '..', 'views')) // 放视图的文件
app.engine("html", nunjucks.configure('views',{
autoescape: true, //(默认值: true) 控制输出是否被转义
throwOnUndefined: false, //(default: false) 当输出为 null 或 undefined 会抛出异常
trimBlocks: false, // (default: false) 自动去除 block/tag 后面的换行符
lstripBlocks: false, //(default: false) 自动去除 block/tag 签名的空格
watch: true, //(默认值: false) 当模板变化时重新加载。使用前请确保已安装可选依赖 chokidar。
express: app //传入 express 实例初始化模板设置
}).render);
app.setViewEngine('html');
await app.listen(3000);
}
bootstrap();
noCache: (default: false) 不使用缓存,每次都重新编译
web: 浏览器模块的配置项
useCache: (default: false) 是否使用缓存,否则会重新请求下载模板
async: (default: false) 是否使用 ajax 异步下载模板
tags: (默认值: see nunjucks syntax) 定义模板语法,
svg-captcha(验证码)
在node.js中生成svg格式的验证码
npm install --save svg-captcha
//nestjs中引入
var svgCaptcha = require('svg-captcha');
app.get('/captcha', function (req, res) {
var captcha = svgCaptcha.create();
req.session.captcha = captcha.text;
res.type('svg');
res.status(200).send(captcha.data);
});
md5(加密)
npm install md5 --save
silly-datetime(时间格式化)
npm i silly-datetime --save
nest-mongoose
安装
npm install --save @nestjs/mongoose mongoose
配置数据库
app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
@Module({
imports: [MongooseModule.forRoot('mongodb://admin:123456@172.0.0.1:27017/millet?authSource=admin', { useNewUrlParser: true })],
})
export class AppModule {}
nest中的增删改查
schema.ts
import * as mongoose from 'mongoose';
const d = new Date();
export const RoleSchema = new mongoose.Schema({
title:{
type:String
},
description:{
type: String
},
status:{
type:Number,
default:1
},
add_time:{
type:Number,
default:d.getTime()
}
})
module.ts
import {RoleService} from './../../service/role/role.service';
@Module({
imports:[MongooseModule.forFeature([
{ name:'Role',schema: RoleSchema,collection:'role'}
])],
controllers: [MainController, LoginController, ManagerController],
providers:[ToolsService,AdminService,RoleService]
})
export class AdminModule {}
interface.ts
export interface RoleInterface {
_id?:String,
title?:String,
description?:String,
status?:Number,
}
service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import {RoleInterface} from './../../interface/role.interface';
@Injectable()
export class RoleService {
constructor(@InjectModel('Role') private readonly roleModel){}
/**
* 查询
* @param json
* @param fields
*/
async find(json:RoleInterface,fields?:string){
try {
return await this.roleModel.find(json,fields);
} catch (error) {
return null;
}
}
/**
* 新增
* @param json
*/
async add(json:RoleInterface){
try {
const role = new this.roleModel(json)
return await role.save()
} catch (error) {
return null;
}
}
/**
* 更新
* @param orginJson
* @param newJson
*/
async update(orginJson:RoleInterface,newJson:RoleInterface){
try {
return await this.roleModel.updateOne(orginJson,newJson)
} catch (error) {
return null;
}
}
/**
* 删除
* @param json
*/
async delete(json:RoleInterface){
try {
return await this.roleModel.deleteOne(json)
} catch (error) {
return null;
}
}
}