72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
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();
|
||
});
|
||
}
|
||
}
|