nestjs学习笔记---小黑是小白

nestjs基础

安装nestjs

 npm i -g @nestjs/cli
 nest new project-name
介绍地址
nestjs中文网nestjs中文
小满nest小满nestjs
typescript中文网ts中文
小满ts小满ts

可能的问题

1.因为在此系统上禁止运行脚本。
有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
首次在计算机上启动 Windows PowerShell 时,现用执行策略很可能是 Restricted(默认设置)。Restricted 策略不允许任何脚本运行。
win+x 打开PowerShell(管理员)

set-ExecutionPolicy RemoteSigned //设置为打开,键入Y或者A,同意
get-executionpolicy//查看是否更改成功,为RemoteSigned表示成功

2.配置eslint后运行项目有如下警告(换行格式问题):Delete `␍`eslintprettier/prettier,执行以下命令(可以自动修复这些问题):
npm run lint --fix

或者
在VScode的设置里搜eol,修改

或者
下载vscode插件:
EditorConfig for VS Code
在项目根目录新建 .editorconfig

root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

原因
在window系统中,clone代码下来,会自动把换行符LF(linefeed character) 转换成回车符CRLF(carriage-return character)。这时候我们本地的代码都是回车符。如果没有加eslint,提交代码的时候,项目的仓库默认是Linux环境下提交的代码,就会提示将会覆盖换行符为LF。使用了eslint并有进行规则配置或者prettier的.prettierrc有进行配置结尾换行符,那么就会直接在开发环境中进行验证。就会提示上述错误(警告)。

基本介绍

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
// 主路由
@Controller('zxj')
export class AppController {
  constructor(private readonly appService: AppService) {}
  // 分路由
  @Get('nb')
  // 下面的方法名可以随便起,无影响,但是要和服务中的一致
  getHello(): string {
    return this.appService.getHello();
  }
}

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
//路由(控制器)和服务通过Module链接
@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return '赵新杰nb!';
  }
}

nest的基本命令

nest–help

nest --help命令用于获取关于Nest CLI(Command Line Interface)的帮助信息。它将显示Nest CLI的可用命令列表以及每个命令的详细描述。基本上命令都是nest g开头

nest g ???

命令

示例:
要在项目终端上使用
user是要放的目录,如果没有就会自动创建一个

nest g co user
name命令alias别名description 介绍
applicationapplicationGenerate a new application workspace
classclGenerate a new class
configurationconfigGenerate a CLI configuration file
controllerco创建控制器路由
modulemo创建模型连接路由和服务
services创建服务
resourceres一键生成上面三个
decoratordGenerate a custom decorator
filterfGenerate a filter declaration
gatewaygaGenerate a gateway declaration
guardguGenerate a guard declaration
interceptoritcGenerate an interceptor declaration
interfaceitfGenerate an interface
librarylibGenerate a new library within a monorepo
middlewaremi创建中间件
pipepi创建管道,用于检验和修改数据使用
providerprGenerate a provider declaration
resolverrGenerate a GraphQL resolver declaration
sub-appappGenerate a new application within a monorepo

请求传值

GET请求

get请求的@Request()

这种在url中传参的方式叫做get的params传参,和get的接参prama不是一个类型,但是相似

127.0.0.1:3000/user?name=123
127.0.0.1:3000/you?name=123&id=123多参用&连接
参数在Request.query里
由@Request() req接参
接到{name:123}

@Get()
  findAll(@Request() req) {
    return req.query.name;
  }

get请求的@Query()

语法糖
@Query()对比@Request()
就是query对比req.query
@Query(‘name’)里可以直接接参数,直接读值

@Get()
  findAll(@Query() query) {
    return query.name;
  }

@Get()
  findAll(@Query(name) name) {
    return name;
  }

动态请求

get请求的@Param(‘id’)

上面的相当于键值在url里都定义好了,这Param('id')相当于接收值,然后再后端命名

http://127.0.0.1:3000/you/1
参数在路由里@Get(‘:id’)
由@Param(‘id’)接受并命名

@Get(':id')
  findOne(@Param('id') id: string) {
    return this.youService.findOne(+id);
  }

POST请求

post请求的@Request()

127.0.0.1:3000/you
{ “name”:“123”,“age”:18} 一般以json格式传送,基本都要"键":“值”
参数在请求体body里

@Post()
  findAll(@Request() req) {
    return req.body;
  }

post请求的@Body()

语法糖
@Body()对比@Request()
就是body对比req.body
@Body(‘name’)里可以直接接参数,直接读值

@Post()
  findAll(@Body() body) {
    return body;
  }

@Post()
  findAll(@Body('name') name) {
    return name;
  }

设置静态资源

根目录下创建public文件夹,放入一张图片

在main.ts引入http平台

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
// 1.引入NestExpressApplication
import { NestExpressApplication } from '@nestjs/platform-express';

async function bootstrap() {
  // 2.加入到create
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  // 3.配置静态资源目录
  app.useStaticAssets('public');
  await app.listen(3000);
}
bootstrap();

进阶:配置虚拟路径的2种方法

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { join } from 'path';
// 1.引入NestExpressApplication
import { NestExpressApplication } from '@nestjs/platform-express';

async function bootstrap() {
  // 2.加入到create
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  // 3.配置静态资源目录
  // app.useStaticAssets('public');
  
  // 3.1 设置虚拟路径
  // app.useStaticAssets('public', {
  //   prefix: '/static/'
  // })

  /* 
   * 3.1.2 设置虚拟路径2 
   * 注:需要引入import { join } from 'path';
   * 访问连接:http://localhost:3000/static/2.jpg
   */
  app.useStaticAssets(join(__dirname, '..', 'public'), {
    prefix: '/static/'
  })
  
  await app.listen(3000);
}
bootstrap();

模板引擎

cookie

npm install cookie-parser --save

配置
main.ts 中引入 cookie-parser

import * as cookieParser from 'cookie-parser' 

在 main.ts 配置中间件

app.use(cookieParser()); 

设置cookie

res.cookie('username', '我是cookie', {maxAge: 1000*60*10, httpOnly: true})

获取cookies

@Get('cookie')
getCookie(@Request() req){
    console.log(req.cookies.username);
    return req.cookies.username;

cookie加密

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { join } from 'path';
import * as cookieParser from 'cookie-parser';

async function bootstrap() {
  // ...
  
  // 配置cookie中间件,()里面写上东西
  app.use(cookieParser('this signed cookies'));
  await app.listen(3000);
}
bootstrap();

. 在article.controller中添加加密cookie

import { Controller, Get, Response } from '@nestjs/common';
@Controller('article')
export class ArticleController {
    @Get()
    index(@Response() res){
        // 设置cookie,signed启用加密
        res.cookie('username', '我是cookie', {maxAge: 1000*60*10, httpOnly: true, signed: true})
        // 注:res和return不能同时使用,否则卡死
        // return '这是文章页面'; 
        res.send('这是文章页面');
           }
}

3.读取cookie

import { Body, Controller, Get, Post, Render, Response, Request } from '@nestjs/common';
@Controller('user')
export class UserController {
    // ...
    // 获取cookie
    @Get('cookie')
    getCookie(@Request() req){
        // 1. 获取普通cookie
        // console.log(req.cookies.username);

        // 2. 获取加密cookie
        console.log(req.signedCookies.username);
        return req.signedCookies.username;
    }
}

session

session 是服务器 为每个用户的浏览器创建的一个会话对象 ,这个session 会记录到 浏览器的 cookie 用来区分用户

我们使用的是nestjs 默认框架express 他也支持express 的插件 所以我们就可以安装express的session

npm i express-session --save

需要智能提示可以装一个声明依赖

npm i @types/express-session -D

然后在main.ts 引入 通过app.use 注册session

import * as session from 'express-session'
app.use(session())
参数配置详解
secret成服务端session 签名 可以理解为加盐
name生成客户端cookie 的名字 默认 connect.sid
cookie返回到前端 key 的属性,默认值为{ path: ‘/’, httpOnly: true, secure: false, maxAge: null }。
rolling在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)

nestjs 配置

import { NestFactory } from '@nestjs/core';
import { VersioningType } from '@nestjs/common';
import { AppModule } from './app.module';
import * as session from 'express-session'
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.enableVersioning({
    type: VersioningType.URI
  })
  app.use(session({ secret: "加密的私钥", name: "session的名字", rolling: true, cookie: { maxAge: null } }))
  await app.listen(3000);
}
bootstrap();

示例

<template>
     <div class="wraps">
          <el-form :label-position="labelPosition" label-width="100px" :model="formLabelAlign" style="max-width: 460px">
               <el-form-item label="账号">
                    <el-input v-model="formLabelAlign.name" />
               </el-form-item>
               <el-form-item label="密码">
                    <el-input type="password" v-model="formLabelAlign.password" />
               </el-form-item>
               <el-form-item label="验证码">
                    <div style="display:flex">
                         <el-input  v-model="formLabelAlign.code" />
                         <img @click="resetCode" :src="codeUrl" alt="">
                    </div>
               </el-form-item>
               <el-form-item>
                    <el-button @click="submit">登录</el-button>
               </el-form-item>
          </el-form>
     </div>
</template>
     
<script setup lang='ts'>
import { onMounted, reactive, ref } from 'vue';
 
const codeUrl = ref<string>('/api/user/code')
 
const resetCode = () => codeUrl.value = codeUrl.value + '?' + Math.random()
 
const labelPosition = ref<string>('right')
 
const formLabelAlign = reactive({
     name: "",
     password: "",
     code: ""
})
 
const submit = async () => {
     await fetch('/api/user/create', {
          method: "POST",
          body: JSON.stringify(formLabelAlign),
          headers: {
               'content-type': 'application/json'
          }
     }).then(res => res.json())
}
 
 
 
</script>
     
<style>
* {
     padding: 0;
     margin: 0;
}
 
.wraps {
     display: flex;
     justify-content: center;
     align-items: center;
     height: inherit;
}
 
html,
body,
#app {
     height: 100%;
}
</style>

import { Controller, Get, Post, Body, Param, Request, Query, Headers, HttpCode, Res, Req } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import * as svgCaptcha from 'svg-captcha';
@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) { }
  @Get('code')
  createCaptcha(@Req() req, @Res() res) {
    const captcha = svgCaptcha.create({
      size: 4,//生成几个验证码
      fontSize: 50, //文字大小
      width: 100,  //宽度
      height: 34,  //高度
      background: '#cc9966',  //背景颜色
    })
    req.session.code = captcha.text 
    //存储验证码记录到session,可以看到session是保持在服务器中,在请求中加入的,同时会给客户端下发一个加密的cookie
    res.type('image/svg+xml')
    res.send(captcha.data)
  }
 
  @Post('create')
  createUser(@Req() req, @Body() body) {
    console.log(req.session.code, body)
    if (req.session.code.toLocaleLowerCase() === body?.code?.toLocaleLowerCase()) {
      return {
        message: "验证码正确"
      }
    } else {
      return {
        message: "验证码错误"
      }
    }
 
  }
}

cookie和session的区别

Cookie和Session都是用于在Web应用中存储用户的状态信息的方式,但它们有一些不同之处。在下面,我将详细介绍Cookie和Session之间的区别。

  1. 存储位置:Cookie是存储在客户端(浏览器)的一小段文本数据,而Session是存储在服务器上的对象。

  2. 数据安全性:由于Cookie是存储在客户端,所以它可以被用户修改和篡改,因此它的安全性较低。而Session存储在服务器上,只有Session ID会被存储在Cookie中,所以Session的安全性较高。

  3. 存储容量:Cookie的存储容量通常较小,一般为4KB左右,而Session的存储容量通常没有明确的限制,可以根据服务器的配置进行调整。

  4. 存储方式:Cookie是将数据存储在客户端的浏览器中,每次请求时都会在HTTP请求头中携带Cookie信息。而Session是将数据存储在服务器上,每次请求时只需携带Session ID,服务器会根据Session ID来获取对应的Session数据。

  5. 生命周期:Cookie可以设置一个过期时间,在过期时间之前一直有效,即使用户关闭了浏览器,Cookie也可以保存下来。而Session的生命周期通常由服务器端控制,一般会在用户关闭浏览器或长时间不活动后过期。

总之,Cookie适用于存储较小的、不敏感的数据,并且需要在多个页面间传递;而Session适用于存储较大的、敏感的数据,并且仅在服务器端使用。

文件上传

单文件上传

npm i -D @types/multer

@types/multer 这两个需要安装,加强ts类型的
@nestjs/platform-express nestJs自带了

import {UploadedFile, UseInterceptors} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import * as fs from 'fs';
import * as path from 'path';




 @Post('upload')
  //import { FileInterceptor } from '@nestjs/platform-express';引入
  //FileInterceptor('file')拦截器中的名字要和上传文件时的表单字段名一致
  //@UploadedFile()即是拦截器从body中拦截的数据
  @UseInterceptors(FileInterceptor('file'))
  uploadFile(@UploadedFile() file) {
    //在fs中创建一个写入流,将文件写入到指定路径
    const writeStream = fs.createWriteStream(
      //再引入path模块,实现路径的拼接
      path.join(__dirname, '../../public/uploads/', file.originalname),
    );
    //将buffer文件写入到指定路径
    writeStream.write(file.buffer);
    return writeStream;
  }


同名的多文件上传

此时的文件拦截器FilesInterceptor 和UploadedFiles修饰器已经是复数形式

  @Post('uploads')
  //import { FilesInterceptor } from '@nestjs/platform-express';引入
  //FilesInterceptor('file')拦截器中的名字要和上传文件时的表单字段名一致
  //@UploadedFiles()即是拦截器从body中拦截的数据
  @UseInterceptors(FilesInterceptor('file'))
  uploadFiles(@UploadedFiles() files) {
    for (const file of files) {
      //在fs中创建一个写入流,将文件写入到指定路径
      const writeStream = fs.createWriteStream(
        //再引入path模块,实现路径的拼接
        path.join(__dirname, '../../public/uploads/', file.originalname),
      );
      //将buffer文件写入到指定路径
      writeStream.write(file.buffer);
    }
    return '上传成功';
  }

中间件

nest风格的中间件

nest g mi middleware/init
nest g mi创建中间件
middleware/init,指定位置

import { Injectable, NestMiddleware } from '@nestjs/common';

@Injectable()
export class InitMiddleware implements NestMiddleware {
  use(req: any, res: any, next: () => void) {
    console.log(Date.now());
    next();
  }
}

在主模块引入

import { Module, NestModule, MiddlewareConsumer , RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { InitMiddleware } from './middleware/init/init.middleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(InitMiddleware)
      .forRoutes(
        { path: 'new', method: RequestMethod.ALL },
        { path: 'id', method: RequestMethod.ALL },
      );
  }
}

函数式中间件

还有函数式中间件和全局中间件,使用方法类似express
先把 logger 转换成函数。

//logger.middleware.ts

export function logger(req, res, next) {
  console.log(`Request...`);
  next();
};
Copy to clipboardErrorCopied
现在在 AppModule 中使用它。

app.module.ts

consumer
  .apply(logger)
  .forRoutes(CatsController);

当您的中间件没有任何依赖关系时,我们可以考虑使用函数式中间件。

多个中间件,为了绑定顺序执行的多个中间件,我们可以在 apply() 方法内用逗号分隔它们。

consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);

全局中间件

如果我们想一次性将中间件绑定到每个注册路由,我们可以使用由INestApplication实例提供的 use()方法:

const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);
  • 47
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值