http body에 json 사용해서 메시지 보내는 경우
Content-Type : application/json
파일 전송하는 경우
Content-Type : multipart/form-data
파일 업로드 하기 전에
BUCKET_NAME은 검색 -> S3에서 확인 가능
src/config/s3Config.ts
const s3: AWS.S3= new AWS.S3({
accessKeyId: config.s3AccessKey,
secretAccessKey: config.s3SecretKey,
region: 'ap-northeast-2'
})
export default s3;
aws-sdk 모듈로 AWS.S3을 만들고 export해줌
config/multer.ts
const upload = multer({
storage: multerS3({
s3: s3,
bucket: config.bucketName,
contentType: multerS3.AUTO_CONTENT_TYPE,
acl: 'public-read',
key: function(req: Express.Request, file: Express.MulterS3.File, cb ) {
cb(null, `${Date.now()}_${file.originalname}`);
}
})
})
export default upload
미들웨어로 사용할 multer 만든 뒤에 export
이때 만든 upload는 router에서 미들웨어로 사용됨
router.post('/upload', upload.single('file'), FileController.uploadFileToS3);
router.post('/upload', upload.array('file'), FileController.uploadFilesToS3);
이렇게!
single - 파일 하나만
array - 파일 여러개
multipart/form-data 에 들어온 데이터 중 ‘file’ 필드로 받아옴. 즉, 필드명에 upload.XXX()의 파라미터로 들어오는 것과 동일해야함
const FileSchema = new mongoose.Schema({
link: {
type: String,
required: true
},
fileName: {
type: String,
required: true
},
}, {
timestamps: true
})
export default mongoose.model<FileInfo & mongoose.Document>("File", FileSchema);
export interface FileInfo {
link: string;
fileName: string;
}
File schema 및 interface 생성.
프로퍼티는 파일 url과 file 이름이 필요하다.
+) s3 권한에서 ACL 활성화 해주어야함! 자세한 내용은 밑에
FileController.ts
const uploadFileToS3 = async (req: Request, res: Response) => {
if (!req.file) return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, message.BAD_REQUEST))
const image: Express.MulterS3.File = req.file as Express.MulterS3.File;
const { originalname, location } = image
try {
const data = await FileService.createFile(location, originalname)
res.status(statusCode.CREATED).send(util.success(statusCode.CREATED, message.CREATE_FILE_SUCCESS, data))
} catch (error) {
console.log(error)
res.status(statusCode.INTERNAL_SERVER_ERROR).send(util.fail(statusCode.INTERNAL_SERVER_ERROR, message.INTERNAL_SERVER_ERROR))
}
}
req.file에 image라는 애가 오는데 걔한테 originalname(파일이름), location(파일 link) 프로퍼티가 있나봄
또한 req.file은 기본으로 Express.Multer.File로 추론되어서 MulterS3로 타입단언해야됨
FileResponseDto.ts
export interface FileResponseDto {
_id: mongoose.Schema.Types.ObjectId;
link: string
}
FileService.ts
const createFile = async (link: string, fileName:string): Promise<FileResponseDto> => {
try {
const file = new File({
link,
fileName
});
await file.save();
const data = {
_id: file._id,
link
};
return data
} catch (error) {
console.log(error)
throw error;
}
}
FileRouter.ts
router.post('upload', upload.single('file'), FileController.uploadFileToS3);
FileController.ts
const uploadFilesToS3 = async (req: Request, res: Response) => {
if (!req.files) return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, message.NULL_VALUE));
const images: Express.MulterS3.File[] = req.files as Express.MulterS3.File[];
try {
// 여기 부가설명 아래에 있음
const imageList: {
location: string;
originalname: string;
}[] = await Promise.all(images.map((image: Express.MulterS3.File) => {
return {
location: image.location,
originalname: image.originalname
}
}));
const data = await FileService.createFiles(imageList);
res.status(statusCode.CREATED).send(util.success(statusCode.CREATED, message.CREATE_FILE_SUCCESS, data));
} catch (error) {
console.log(error)
res.status(statusCode.INTERNAL_SERVER_ERROR).send(util.fail(statusCode.INTERNAL_SERVER_ERROR, message.INTERNAL_SERVER_ERROR))
}
}
imageList - location과 originalname이라는 키를 가진 객체의 배열
Promise.all() 메소드를 사용해서 각각의 객체가 전부 준비되면 반환되도록 함
메소드 안에서는 map을 통해 images 배열을 돌면서 location과 originalname이라는 키를 가진 객체를 반환
FileService.ts
const createFiles = async (imageList: { location: string, originalname: string }[]): Promise<FileResponseDto[]> => {
try {
const data = await Promise.all(imageList.map(async image => {
const file = new File({
link: image.location,
fileName: image.originalname
});
await file.save();
return {
_id: file._id,
link: file.link
};
}));
return data;
} catch (error) {
console.log(error)
throw error;
}
}
FileRouter.ts
router.post('/upload', upload.array('file'), FileController.uploadFilesToS3);
s3 검색 -> 해당 bucket 선택 -> 권한 탭 -> 밑으로 쭉 내려서 ACL(액세스 제어 목록) 찾아라 -> ACL 활성화하고 변경사항 저장
버전오류일 수 있다 package.json에서 뭐 버전 수정해보셈 자세한 내용은 슬랙참고
postman에서 body -> form data -> key에 필드명을 file로 하고 왼쪽에 text말고 file로 설정한 뒤에, value에서 파일 선택