web-01-api/src/common/middlewares/upload.middleware.ts
2026-06-22 14:15:56 +08:00

72 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
Injectable,
NestMiddleware,
BadRequestException,
} from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import multer, { Multer } from 'multer';
import path from 'path';
import fs from 'fs';
const ALLOWED_MIME = ['image/jpeg', 'image/png', 'image/webp'];
const MAX_SIZE = 2 * 1024 * 1024; // 2M
/**
* 文件上传中间件(按日期分文件夹)
* 单图字段名固定file
*/
@Injectable()
export class UploadMiddleware implements NestMiddleware {
private readonly upload: Multer;
constructor() {
const root = process.env.UPLOAD_ROOT ?? './uploads';
this.upload = multer({
storage: multer.diskStorage({
destination: (_req, _file, cb) => {
const date = new Date();
const dir = path.join(
process.cwd(),
root.replace(/^\.\/?/, ''),
`${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, '0')}`,
);
fs.mkdirSync(dir, { recursive: true });
cb(null, dir);
},
filename: (_req, file, cb) => {
const ext = path.extname(file.originalname).toLowerCase();
const name = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}${ext}`;
cb(null, name);
},
}),
fileFilter: (_req, file, cb) => {
if (ALLOWED_MIME.includes(file.mimetype)) {
cb(null, true);
} else {
// FileFilterCallback 重载:错误时只传 Error不传 acceptFile
cb(new Error('仅支持 jpg/png/jpeg/webp 格式图片'));
}
},
limits: { fileSize: MAX_SIZE },
});
}
use(req: Request, _res: Response, next: NextFunction): void {
// @types/express 与 @types/multer 内嵌的 @types/express-serve-static-core 版本不一致,
// 运行时完全等价,用 unknown 中转两次绕过编译期差异
const single = this.upload.single('file') as unknown as (
req: Request,
res: Response,
cb: (err: unknown) => void,
) => void;
single(req, _res, (err) => {
if (err) {
const msg = err instanceof Error ? err.message : '文件上传失败';
next(new BadRequestException(msg));
return;
}
next();
});
}
}