定制软件开发Nestjs配置文件上传, 配置中间件以及管道的使用

Nestjs定制软件开发中的文件上传

  • 文档: https://docs.nestjs.com/techniques/file-upload

安装插件

  • $ yarn add @types/multer

示例

1 ) 定制软件开发简单单个上传

  • 前端代码

        <form action="upload/add" method="post" enctype="multipart/form-data">        <input type="file" name="files" />        <br> <br>        <input type="submit" value="提交">    </form>
    • 1
    • 2
    • 3
    • 4
    • 5
  • 后端代码

    import { Controller, Get, Render, Post, Body, UseInterceptors, UploadedFile } from '@nestjs/common';import { FileInterceptor } from '@nestjs/platform-express';import { createWriteStream } from 'fs';import { join } from 'path';@Controller('upload')export class UploadController {    @Get()    @Render('default/upload')    index() {    }    @Post('add')    @UseInterceptors(FileInterceptor('files'))    doAdd(@Body() body, @UploadedFile() file) {        console.log(body);        console.log(file);  //定制软件开发上传图片的信息  必须在form定制软件开发的属性里面配置enctype="multipart/form-data"        const writeStream = createWriteStream(join(__dirname, '../../public/upload', `${Date.now()}-${file.originalname}`))        writeStream.write(file.buffer);        return '定制软件开发上传图片成功';    }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

2 ) 定制软件开发多文件上传

  • 如果field一样(用的name都是files),定制软件开发我们可选择使用 UploadedFiles 定制软件开发的方法来处理,并且通过 for … of 来遍历
  • 如果不一样,则提供了,如下的配置
    @Post('upload')@UseInterceptors(FileFieldsInterceptor([    { name: 'avatar', maxCount: 1 },    { name: 'background', maxCount: 1 },]))uploadFile(@UploadedFiles() files: { avatar?: Express.Multer.File[], background?: Express.Multer.File[] }) {    console.log(files);}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 或者使用Any类型的拦截器AnyFilesInterceptor
    @Post('upload')@UseInterceptors(AnyFilesInterceptor())uploadFile(@UploadedFiles() files: Array<Express.Multer.File>) {    console.log(files);}
    • 1
    • 2
    • 3
    • 4
    • 5
  • 需要注意的是,我们每次上传时,这些路径,图片处理什么的,需要封装一下

Nestjs 中间件

  • 同express一样,nestjs中间件也可以理解为在请求和响应之间的一个管道处理程序
  • 可以是一个函数,也可以是一个@Injectable() 装饰器装饰的类

中间件作用

  • 执行任何代码
  • 对请求和响应对象进行更改
  • 结束请求-响应周期
  • 调用堆栈中的下一个中间件函数
  • 如果当前的中间件函数没有结束请求-响应周期, 它必须调用 next() 将控制传递给下一个中间件函数
  • 否则, 请求将被挂起

中间件的创建和使用

1 ) 创建

  • $ nest g middleware http 这里http是中间件名
  • 会生成src/http.middleware.ts文件,如下:
    import { Injectable, NestMiddleware } from '@nestjs/common';@Injectable()export class HttpMiddleware implements NestMiddleware {    use(req: any, res: any, next: () => void) {        next();    }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 我们按照文档上,改造一下
    import { Injectable, NestMiddleware } from '@nestjs/common';import { Request, Response, NextFunction } from 'express';@Injectable()export class HttpMiddleware implements NestMiddleware {    use(req: Request, res: Response, next: NextFunction) {        console.log('Request...');        next();    }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

2 ) 在app.module.ts中使用

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';import { HttpMiddleware } from './http.middleware';import { CatsModule } from './cats/cats.module'; // 模块@Module({  imports: [CatsModule],})export class AppModule implements NestModule {  configure(consumer: MiddlewareConsumer) {    consumer      .apply(HttpMiddleware)      // .forRoutes('cats'); // 表示哪些路由可以使用这个中间件      // .forRoutes(someController); // 匹配所有的路由 // 或者传入指定控制器,但是不建议这样写       // .forRoutes({path: 'cats', method: RequestMethod.GET}); // 只匹配GET      // .forRoutes({path: 'cats', method: RequestMethod.ALL}); // 匹配所有方法      // .forRoutes({path: 'cats', method: RequestMethod.ALL}, {path: 'user', method: RequestMethod.ALL}); // 配置多个      .forRoutes('*'); // 匹配所有的路由   }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 当然,我们最好把中间件放到一个通用的模块中,如下:./common/middleware/
    import { LoggerMiddleware } from './common/middleware/logger.middleware';
    • 1
  • 其实可以在创建的时候指定目录 $ nest g middleware common/middleware/http.middleware

3 ) 配置多个中间件的示例

3.1 一种配置

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';import { HttpMiddleware } from './http.middleware';import { UserMiddleware } from './user.middleware';@Module({  imports: [],})export class AppModule implements NestModule {  configure(consumer: MiddlewareConsumer) {    consumer      .apply(HttpMiddleware).forRoutes('*')      .apply(UserMiddleware).forRoutes('user')  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3.2 另一种配置

// 这里只写关键代码consumer.apply(NewsMiddleware,UserMiddleware).forRoutes({ path: 'u*r', method: RequestMethod.ALL},{ path: 'news', method: RequestMethod.ALL}) // 这里不讲究顺序
  • 1
  • 2
  • 3
  • 4
  • 5

4 ) 函数式中间件

// 只写关键代码export function logger(req, res, next) {     console.log(`函数式中间件...`);    next();};export class AppModule implements NestModule {  configure(consumer: MiddlewareConsumer) {    consumer      .apply(HttpMiddleware, logger).forRoutes('*')  }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

5 ) 全局中间件

  • 在main.ts中使用,注意不能使用类中间件,只能使用函数中间件

    //全局中间件只能引入函数式中间件import { logger } from './middleware/logger.middleware';app.use(logger);
    • 1
    • 2
    • 3
    • 4

管道

  • 关于管道:https://docs.nestjs.com/pipes
  • 管道的概念是主要用于将输入数据转换为所需的输出数据
  • 或者处理Get,Post提交的数据

创建管道

  • $ nest g pipe cart

  • 或指定路径生成 $ nest g middleware common/pipe/cart.pipe

  • 创建一个cart的管道

    import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';@Injectable()export class CartPipe implements PipeTransform {  transform(value: any, metadata: ArgumentMetadata) {    return value;  }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 说明:管道是由@Injectable()装饰的一个类

  • 需要实现 PipeTransform 这个接口,并且实现其内部的一个 transform 方法

  • 这里有两个参数:value,metadata

  • 其中, value是传递到管道里的数据, metadata是一种类型

  • 在这里面可以修改传入的值以及验证传入值的合法性

使用管道

  • 在控制器中使用管道

    import { Controller, Get, Query, UsePipes} from '@nestjs/common';//引入管道import { CartPipe } from '../../pipe/cart.pipe';@Controller('cart')export class NewsController {    @Get()    @UsePipes(new CartPipe())    index(@Query() info){        console.log(info);        return 'Cart'    }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 由上面的代码可知,先要引入管道,之后使用UsePipes将引入的管道实例作为参数作为当前路由的一项装饰器

  • 这里的info就会被传入到管道里面,也就是管道里的value参数

  • 之后,在管道里就可以针对当前的值进行修改,校验等操作

关于管道中的校验

  • 在接收到数据前,需要对数据进行一些校验等操作,这时候就比较适合在管道中写相关程序

  • 一般而言,我们会借助第三方的库来帮助我们完成校验,官方给我们提供了使用joi库相关的示例

  • https://github.com/hapijs/joi,https://joi.dev/api/?v=17.6.0

  • 下面做一下演示

    // 控制器文件中使用import { Controller, Get, Query, UsePipes } from '@nestjs/common';import { UserPipe } from '../../pipe/user.pipe';import * as Joi from 'joi';// 定义 json schemaconst userSchema = Joi.object().keys({    name: Joi.string().required(),    age: Joi.number().integer().min(6).max(66).required(),})@Controller('user')export class UserController {    @Get()    @UsePipes(new UserPipe(userSchema))    index(@Query() info) {        console.log(info);        return '用户中心';    }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    // 在管道文件中import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';@Injectable()export class UserPipe implements PipeTransform {  private schema;  constructor(schema){    this.schema=schema // 实例化的时候,参数传入  }  transform(value: any, metadata: ArgumentMetadata) {    const { error } = this.schema.validate(value); // 进行校验    // 如果错误,则提示,或统一返回相同的实体数据结构, 比如给前端提示    if(error) {      return {"success": false};    }    return value;      }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 上面是基础用法,当然一般而言,也可以添加相关message信息,用于给前端用户提示

  • 更多用法,请参考上面文档

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发