Skip to content

Nest 实现多图上传

前端

特别注意

注意

使用 FormData 和 fetch API 上传图片(示例代码,需要根据后端 API 调整) const formData = new FormData(); formData.append("module", "books"); // 添加其他字段,例如文件名 formData.append("image", file); // 'image' 是后端期待的字段名,根据需要调整

代码

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>多图片上传</title>
  </head>
  <body>
    <input type="file" id="imageInput" multiple accept="image/*" />
    <button onclick="uploadImages()">上传图片</button>
    <div id="uploadStatus"></div>
  </body>
  <script>
    function uploadImages() {
      const files = document.getElementById("imageInput").files;
      const formData = new FormData();
      const statusDiv = document.getElementById("uploadStatus");
      statusDiv.innerHTML = ""; // 清除之前的上传状态

      // 检查是否有文件被选择
      if (files.length === 0) {
        statusDiv.innerHTML = "请选择文件";
        return;
      }
      formData.append("module", "user"); // 添加其他字段,例如文件名
      // 遍历所有选中的文件,添加到FormData中
      for (let i = 0; i < files.length; i++) {
        formData.append("image", files[i]);
      }

      // 使用fetch API发送数据到服务器
      fetch("http://localhost:5000/user/upload", {
        // 替换为你的服务器端点URL
        method: "POST",
        body: formData,
      })
        .then((response) => response.json()) // 假设服务器返回JSON格式的响应
        .then((data) => {
          if (data.code == 200) {
            alert("上传成功");
          } else {
            alert("上传失败");
          }
        })
        .catch((error) => {
          console.error("Error:", error);
          statusDiv.innerHTML = "上传失败"; // 更新状态显示上传失败
        });
    }
  </script>
</html>

Nest 前置

安装依赖

bash

npm install --save @nestjs/platform-express multer

npm install -D @types/multer

storage.ts

  • 根目录创建 utils/storage.ts
ts
import * as multer from "multer";
import * as path from "path";
import * as fs from "fs";

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const dir = path.join(__dirname, "../../", "public/ceshiupload");
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
    cb(null, dir);
  },
  filename: (req, file, cb) => {
    const randomName = Array(32)
      .fill(null)
      .map(() => Math.round(Math.random() * 16).toString(16))
      .join("");
    return cb(null, `${randomName}${path.extname(file.originalname)}`);
  },
});
/**
 * @param { delPath:String } (需要删除文件的地址)
 * @param { direct:Boolean } (是否需要处理地址)
 */
const deleteFile = (delPath, direct) => {
  delPath = direct ? delPath : path.join(__dirname, delPath);
  try {
    /**
     * @des 判断文件或文件夹是否存在
     */
    if (fs.existsSync(delPath)) {
      console.log(delPath);
      fs.unlinkSync(delPath);
    } else {
      console.log("inexistence path:", delPath);
    }
  } catch (error) {
    console.log("del error", error);
  }
};

export { storage, deleteFile };

创建上传模块

  • upload.module.ts
ts
import { Module, Global } from "@nestjs/common";
import { UploadService } from "./upload.service";
import { UploadController } from "./upload.controller";

@Global()
@Module({
  controllers: [UploadController],
  providers: [UploadService],
  exports: [UploadService],
})
export class UploadModule {}

创建上传控制器

  • upload.controller.ts
ts
import { Controller } from "@nestjs/common";

@Controller("upload")
export class UploadController {}

创建上传提供者

  • upload.service.ts
ts
import { HttpException, Inject, Injectable } from "@nestjs/common";
import { deleteFile } from "../../utils/storage";
@Injectable()
export class UploadService {
  async findone(files, pathname) {
    if (files["status"] == 403) {
      for (let i = 0; i < files["value"].length; i++) {
        deleteFile(files["value"][i].path, true);
      }
      return {
        code: 403,
        data: "",
        message: files["data"],
      };
      // throw new HttpException(files['message'], 403);
    } else {
      const url: string[] = [];
      files.forEach((item) => {
        url.push(
          "http://localhost:5000/public/images/" +
            pathname +
            "/" +
            item.filename
        );
      });
      return {
        url,
      };
    }
  }
}

创建管道验证

  • upload.pipe.ts
ts
import { ArgumentMetadata, Injectable, PipeTransform } from "@nestjs/common";

@Injectable()
export class UploadPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    if (value.length > 0) {
      let count = 0;
      let type = 0;
      // 多图
      value.map((item: any) => {
        // 判断大小
        if (item.size > 1024 * 1024 * 10) {
          count++;
        }
        // 判断类型
        if (item.mimetype.indexOf("image") == -1) {
          type++;
        }
      });
      if (count > 0) {
        return {
          status: 403,
          data: "图片大小不能超过10M",
          value: value,
        };
      }
      if (type > 0) {
        return {
          status: 403,
          data: "必须是图片",
          value: value,
        };
      }
      return value;
    } else {
      // 单图
      if (value.size > 1024 * 1024 * 10) {
        return {
          status: 403,
          data: "图片大小不能超过10M",
          value: value,
        };
      }
      if (value.mimetype.indexOf("image") == -1) {
        return {
          status: 403,
          data: "必须是图片",
          value: value,
        };
      }
      return value;
    }
  }
}

Nest 使用

  • 其他使用的 controller 中引入
ts

import {
  Controller,
  Post,
  Body,
  UseInterceptors,
  UploadedFiles,
} from '@nestjs/common';
import { UserService } from './user.service';
import { FilesInterceptor } from '@nestjs/platform-express';
import { UploadService } from '../upload/upload.service';
import { UploadPipe } from '../../pipe/upload.pipe';
import { storage } from '../../utils/storage';
// 上传
  @Post('upload')
  @UseInterceptors(
   // 上传 要是文件的话image 换成 file 前端对应的image也换成file
    FilesInterceptor('image', 3, {
      storage: storage,
    }),
  )
  async upload(
    @Body() body: any,
    @UploadedFiles(UploadPipe)
    files: Array<Express.Multer.File>,
  ) {
    let name = body.module;

    return this.UploadService.findone(files, name);
  }