직전 타입스크립트 개인과제를 진행하면서 만들어 둔 업로드 미들웨어를 이번 팀프로젝트때 적용하려 했는데 form-data에 들어있는 값을 읽지 못하고, file에 location을 찾을 수 없다는 현상이 발생했다.
// upload-middleware.ts
import { HttpStatus, Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import * as multer from 'multer';
import * as multerS3 from 'multer-s3';
import * as AWS from 'aws-sdk';
import * as path from 'path';
import { uuid } from 'uuidv4';
@Injectable()
export class UploadMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
try {
const s3 = new AWS.S3({
accessKeyId: process.env.S3_ACCESS_KEY,
secretAccessKey: process.env.S3_ACCESS_KEY_SECRET,
region: process.env.AWS_REGION,
});
const allowedExtensions = ['.png', '.jpg', '.jpeg', '.jfif', '.exif', '.tiff', '.bmp', '.gif'];
const upload = multer({
storage: multerS3({
s3,
bucket: process.env.BUCKET_NAME,
contentType: multerS3.AUTO_CONTENT_TYPE,
shouldTransform: true,
key: function (_, file, callback) {
const fileId = uuid();
const type = file.mimetype.split('/')[1];
if (!allowedExtensions.includes(path.extname(file.originalname.toLowerCase())) || !file.mimetype.startsWith('image/')) {
const errorMessage = '이미지 파일만 업로드가 가능합니다.';
const errorResponse = { errorMessage };
return res.status(HttpStatus.BAD_REQUEST).json({ errorResponse });
}
const fileName = `${fileId}.${type}`;
callback(null, fileName);
},
acl: 'public-read-write',
limit: { fileSize: 5 * 1024 * 1024 },
}),
});
upload.single('newFile')(req, res, next);
} catch (error) {
console.error(error);
res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ errorMessage: '파일 업로드 에러' });
}
}
}
이게 직전 프로젝트에서 사용하던 것인데 location을 찾을 수 없다는 에러는 직접 index.d.ts파일을 만들어서 type을 지정해주고 해결했었던 문제였다.
//index.d.ts
declare namespace Express {
export interface Request {
file: Express.Multer.File;
user: { userId: number; isAdmin: boolean };
}
}
그래서 이번에도 타입을 직접 지정해줘야하나 싶어 추가해봤는데 추가를 해도 계속 Multer를 찾을 수 없다는 에러가 발생하여 이것저것 찾아보다 팀원분에게 여쭤보고 해결방법을 찾았다.
// 내가 적용했던 코드
import { Request } from 'express';
import { User } from '../entities/user.entity';
export interface IRequest extends Request {
user?: User;
file: Express.Multer.File
}
이 부분에서 처음엔 Multer를 찾을 수 없다고 나오다가 vscode를 껐다키니 Request를 확장하여 사용할 수 없다는 에러가 발생하여 아래와 같이 수정하여 해결
import { Request } from 'express';
import { User } from '../entities/user.entity';
export interface IRequest extends Request {
user?: User;
file: any;
}
먼저 file을 any타입으로 변경해주고
// upload-middleware.ts
key: function (_, file: Express.Multer.File, callback) {
const fileId = uuid();
const type = file.mimetype.split('/')[1];
업로드 미들웨어의 file을 Express.Multer.File로 직접 넣어주니 req.file.location을 읽어올 수 있었다.
다음은 form-data의 값을 가져올 수 없는 문제가 있어서 nest-form-data 패키지를 다운받고 데코레이터를 적용했더니 unexpected end of form이라는 오류가 발생했다.
stackoverflow에 나와 같은 문제를 겪은 사람이 많아 댓글을 읽어보니 multer의 버전을 1.4.3을 사용하면 된다해서 @types/multer의 버전을 1.4.3으로 다운그레이드 후 nest-form-data패키지를 삭제하고 실행해보니 정상작동했다.
이렇게 유용한 정보를 공유해주셔서 감사합니다.