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/multerstorage.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);
}