IT/Aws

S3 file upload with Presigned url

Full~ day ๐Ÿ˜€ 2022. 11. 22. 17:13
728x90
๋ฐ˜์‘ํ˜•
 
1.s3 Presigned url 
2.react file upload
 

 

nodejs๋ฅผ ํ†ตํ•ด์„œ s3๋กœ ํŒŒ์ผ ์—…๋กœ๋“œ ๋ฐฉ๋ฒ•์€ s3.update() putobject ๋“ฑ๋“ฑ ์žˆ๋Š”๊ฑธ๋กœ ์•ˆ๋‹ค

ํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ด์œ ์ค‘ ํŒŒ์ผ ์šฉ๋Ÿ‰๋Œ€๋น„ ์—…๋กœ๋“œ ์‹œ๊ฐ„์„ ๊ณ ๋ คํ•˜์—ฌ ๋ฐฑ์—”๋“œ๋ฅผ ๊ฑฐ์น˜์น˜์•Š๊ณ  ๋ฐ”๋กœ s3๋ฒ„ํ‚ท์œผ๋กœ ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•  ํ•„์š”๊ฐ€ ์ƒ๊ฒผ๋‹ค. ์šฉ๋Ÿ‰์ด 100mb์ด์ƒ์€ ์•„๋‹ˆ๋ผ์„œ ๋ฏธ๋ฆฌ์„œ๋ช…๋œ(presigned) url api ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค. ๋‚˜์ค‘์— ๊ณ ์šฉ๋Ÿ‰ ํŒŒ์ผ์„ ์˜ฌ๋ฆด๋•Œ์—๋Š”   multipartupload๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž‘์—… ํ›„ ๊ธ€์„ ์ž‘์„ฑํ•  ์˜ˆ์ •์ด๋‹ค.

 

s3 ์„ค์ •

๊ธฐ๋ณธ์„ค์ •์€ ๋˜‘๊ฐ™๋‹ค

https://bae-ha.tistory.com/23

 

React+Node+S3 upload download

1.Node,S3 download upload 2.React 1.Node์„ค์ • aws ์„ค์ • aws.js const AWS = require("aws-sdk"); const multer = require("multer"); const s3 = new AWS.S3({ accessKeyId: process.env.AWS_KEY, secretAccessKey: process.env.AWS_SEC_KEY, region: "ap-northeast-2",

bae-ha.tistory.com

 

presignedUrl

 

presigned.js

const getSignedUrl = ({ key }) => {
  return new Promise((resolve, reject) => {
    s3.createPresignedPost(
      {
        Bucket: BUCKET,
        Fields: {
          key,
        },
        Expires: 30,
        Conditions: [
          ["content-length-range", 0, 50 * 1024 ** 2],  
          ["starts-with", "$Content-Type", ""]
        ],
      },
      (err, data) => {
        if (err) reject("err");
        resolve(data);
      }
    );
  });
};

createPresignedPost๋ฅผ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š” file ์šฉ๋Ÿ‰์„ ์ œํ•œํ•˜๊ธฐ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๊ธฐ์กด์— getSignedUrl์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜์˜€์ง€๋งŒ file์šฉ๋Ÿ‰ ์„ค์ •๊ธฐ ์—†๋Š”๊ฒƒ ๊ฐ™์•„์„œ ์ด๋ฒˆ์—๋Š” createPresignedPost ์‚ฌ์šฉํ•˜์˜€๋‹ค.

content-length-range๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์šฉ๋Ÿ‰์„ ์ œํ•œํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  content-type์„ ๋„ฃ์€์ด์œ ๋Š” ๋‚˜์ค‘์— s3์—…๋กœ๋“œํ• ๋•Œ ํ™•์žฅ์ž๋ฅผ ๋”ฐ๋กœ ๋ถ™์ด์ง€์•Š๊ณ  uuidํ˜•์‹์œผ๋กœ ํŒŒ์ผ์ด๋ฆ„์„ ์ €์žฅํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋•Œ ํ•ด๋‹น ํŒŒ์ผ์ด ์–ด๋–ค ํƒ€์ž…์ด ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

 

get presignedUrl 

const files = [...ํŒŒ์ผ ๋ฐ์ดํ„ฐ๋“ค]

const getPresigned = await Promise.all(
  files.map(async(file) => {
    const fileKey = uuid();
    const key = `{path}/${fileKey}`;
    const presigned = await getSignedUrl({key})
    return {imageKey, presigned}
  })
)

์ด๋ ‡๊ฒŒ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด ํŒŒ์ผ ๊ฐœ์ˆ˜ ๋งŒํผ presignedUrl ์ด ์ƒ์„ฑ ๋œ๋‹ค.

์ƒ์„ฑ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์ œ react์—์„œ httpํ†ต์‹ ๋งŒ ์ง„ํ–‰ํ•˜๋ฉด ๋œ๋‹ค.

 

React

 

response = url ๋ฐ์ดํ„ฐ๋“ค..

const files = [...file ๋ฐ์ดํ„ฐ๋“ค]

const result = await Promise.all(
  [...files].map(async (file, index) => {
    const presigned = response.getPresigned[index].presigned;

    const formData = new FormData();
    for (const key in presigned.fields) { // *1
      formData.append(key, presigned.fields[key]);
    }
    formData.append("Content-Type", file.type); // *2
    formData.append("file", file); // *3
    const result = await axios.post(presigned.url, formData);
    return result;
  })

 

์ด์ œ nodejs์—์„œ ๋ฐ›์•„์˜จ presignedUrl ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  s3์— ์ง์ ‘ ์—…๋กœ๋“œ๋ฅผ ํ•  ์ฐจ๋ก€์ด๋‹ค.

*1 presignedUrl์— ๋‹ด๊ฒจ์žˆ๋Š” ๊ฐ์ข… ์ •๋ณด๋“ค์ด๋‹ค ์ด๊ฑธ ๋น ์ง์—†์ด ๋‹ค ๋ถ™์—ฌ์ค˜์•ผํ•œ๋‹ค.

for in์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ object์— key๊ฐ’์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค ๊ทธ ๊ธฐ์ค€์œผ๋กœ ๊ฐ’๋„ ํ‘œํ˜„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

*2 ๊ฐ ํŒŒ์ผ์˜ ํƒ€์ž…์„ ์„ค์ •ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ์ด๋‹ค. ์œ„์—์„œ ๋งํ–ˆ๋˜ content type์„ค์ •์ด ์ง€๊ธˆ ์ด ๋ถ€๋ถ„์ด๋‹ค.

*3 ๋งˆ์ง€๋ง‰์œผ๋กœ ํŒŒ์ผ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž…๋ ฅ๋˜๋ฉด ๋์ด๋‹ค.

 

 

728x90
๋ฐ˜์‘ํ˜•
LIST