일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- yolov5
- nodejs
- jwt
- jQuery
- CRUD
- 페이지네이션
- S3
- 파이썬
- 인공지능
- 서류전형
- EC2
- 프로그래머스
- 피로그래밍
- 절차지향
- 사물인식
- 솝트
- 파이썬 #백준 #BFS
- 백준
- 멋쟁이사자처럼
- AWS
- MongoDB
- 카카오
- objectdetection
- 면접전형
- Python
- 멋사
- spring-boot
- 솝트 후기
- Java
- 합격후기
- Today
- Total
찔끔찔끔씩😎
[Sopt] 7차 세미나(1) - Nodjs AWS S3 파일 업로드 본문
IMAGE UPLOAD
🔎 Content type
HTTP Body 에 들어가는 Message의 Type 을 명시해주어야 한다.
json 형식을 사용하여 HTTP Body를 전송하는 경우의 Content Type으로 지금까지 applicaion/json 을 사용하였다.
그렇다면 파일은 어떤 형식으로 전송해야 할까?
바로 multipart/form-data 를 사용하면 된다. Content-Type 필드에 MIME Type 을 명시하기 위한 Content-type file 전송을 위해 사용한다.
🔎 Upload Flow
Client-Server 사이의 업로드 과정에 대해 알아보자.
1. 클라이언트는 Form 을 통하여 파일을 서버로 전송한다.
2. 이때 Content-Type은 multipart/form-data로 지정되어 전송된다.
3. 서버는 해당 multipart 메세지를 part 별로 분리하여 처리한다.
🔎 사용할 모듈
- multer: multipart/form-data로 전송된 파일을 처리하는 미들웨어
- multer-s3: 이미지 업로드 시 S3를 사용할 경우 이용한다.
- aws-sdk: Node.js 용 AWS SDK를 사용하기 위한 모듈
설치해주자!
yarn add multer multer-s3 aws-sdk
yarn add @types/multer-s3 @types/multer --dev
추가적으로 서버에서 AWS에 접근하기 위해서는 Access key가 필요하다.
발급 받은 키와 본인의 S3 버킷 이름을 .env에 추가해주도록 한다.
변수로 사용할 수 있도록 config/index.ts에 정의해준다.
config/s3.Config.ts
aws-sdk 모듈을 이용하여 access key, secret access key, region 을 파라메터로 하는 AWS.S3를 만들어 준다.
이는 AWS와의 연결을 위한 것!
import AWS from "aws-sdk";
import config from ".";
/**
* AWS와 연결을 위해
*/
const s3: AWS.S3 = new AWS.S3({
accessKeyId: config.s3AccessKey,
secretAccessKey: config.s3SecretKey,
region: 'ap-northeast-2'
});
export default s3;
config/multer.ts
import multer from "multer";
import multerS3 from "multer-s3";
import config from ".";
import s3 from "./s3Config";
const upload = multer({ //미들웨어로 사용할 multer 생성
storage: multerS3({
// 실질적인 storage는 multer s3를 사용한다.
// 따라서 aws s3로 설정하고, s3 bucket name을 지정해준다.
s3: s3,
bucket: config.bucketName,
contentType: multerS3.AUTO_CONTENT_TYPE, // multer가 알아서 지정할것
acl: "public-read", // access control for the file
key: function (req: Express.Request, file: Express.MulterS3.File, cb) {
// bucket 내 이름이 겹치면, 동일 파일로 인식하기 때문에
// 시간도 붙여줘서 이름이 같더라도 다른 파일로 저장하게 한다.
cb(null, `${Date.now()}_${file.originalname}`);
},
}),
});
export default upload;
이미지 업로드 (차례대로 단일 이미지, 여러 이미지)
🔎 1. Model, Collection 만들기
File 모델 (src/models/File.ts)
import mongoose from "mongoose";
import { FileInfo } from "../interfaces/file/FileInfo";
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);
FileInfo.ts (src/interfaces/file/FileInfo.ts)
export interface FileInfo {
link: string;
fileName: string;
}
FileResponseDto.ts (src/interfaces/file/FileResponseDto.ts)
import mongoose from "mongoose";
export interface FileResponseDto {
_id: mongoose.Schema.Types.ObjectId;
link: string;
}
🔎 2. Controller 만들기
multer upload 미들웨어에서 s3에 저장된 파일 주소는 req.file.location에 위치한다.
// 단일 파일
// multer upload 미들웨어에서 s3에 저장된 파일 주소는 req.file.location에 위치함
// 미들웨어 만든거 넣어주고, 파일 주소를 저장만 해주면 된다.
const uploadFileToS3 = async (req: Request, res: Response) => {
if (!req.file) return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, message.NULL_VALUE));
const image: Express.MulterS3.File = req.file as Express.MulterS3.File;
// image에서 name,location 받아오기
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));
}
}
// 다중 파일
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));
}
}
export default{
uploadFileToS3,
uploadFilesToS3,
}
🔎3. Service 만들기
// 단일 파일
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;
}
}
// 다중 파일
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();
// file의 id, link를 배열로 반환하기
return {
_id: file._id,
link: file.link
};
}));
return data;
} catch (error) {
console.log(error);
throw error;
}
};
export default {
createFile,
createFiles
}
🔎 4. Router 만들기
upload.single('file'): multipart/form-data에 들어온 데이터 중 'file' 필드로 받아 온다.single: 단일array: 다중
const router: Router = Router();
// router.post('/upload', upload.single('file'), FileController.uploadFileToS3);
// 여러개를 위해 single대신 array로 사용
router.post('/upload', upload.array('file'), FileController.uploadFilesToS3);
export default router;
🔎 multipart/form-data 보내기
이전에는 Json 형식으로만 보냈다면 Form 으로 전송해주어야한다.
🔎 s3 acl 권한 부여
s3 bucket -> 권한 -> ACL -> 편집
'Server > Nodejs' 카테고리의 다른 글
[Sopt] 7차 세미나(2) - Nodejs 검색 기능, 페이지네이션 (0) | 2022.06.18 |
---|---|
[Sopt] 5차 세미나(1) - Middleware, Authentication, API 명세서 (0) | 2022.05.18 |
[Sopt] 4차 세미나(2) - Nodejs API 실습 (0) | 2022.05.18 |
[Sopt] 4차 세미나(1) - AWS EC2, PM2, S3 (0) | 2022.05.17 |
[Sopt] 3차 세미나(2) - NodeJS CRUD 실습✨ (0) | 2022.05.17 |