728x90

base64? buffer? stream?

일반적으로 자주 사용하지는 않으나

파일 처리를 할때면 나타나 곤란한 상황을 만드는 녀석들이다.

 

이번에 우연한기회에

AWS에 업로드된 파일 URL을 노출시키지 않으면서

클라이언트에서 파일을 내려받게 해줘야하는 상황이 발생했다.

 

해당 과정에서 삽질하며 얻은 조각 지식들을 공유한다.

 

[ 가정 ]

1. 클라우드 저장소에 파일이 있다.

2. 클라이언트에서 파일 다운로드 요청 발생.

3. 서버에서 해당 파일을 불러온다.

4. 클라이언트에 해당 파일을 전송한다.

5. 다운로드 실시

 

1.  클라우드 저장소에 파일이 있다.

- AWS의 S3에 특정 파일이 저장되어있는 상황입니다.

- 해당 파일은 비문은 아니지만 공유를 원치않아 파일의 링크는 노출되지 않기를 원합니다.

- 마찬가지로 해당 파일의 버킷은 퍼블릭 버킷이 아닙니다.

- 따라서, 허가된 key를 가진 사용자만 파일을 호출할 수 있습니다. (즉, 서버에서만 요청 가능)

 

2. 파일을 필요로 하는 클라이언트는 지정된 서버로 요청을 보냅니다.

- 지정된 서버는 당연히 해당 AWS계정의 접근권한, key를 가진 서버겠죠.

 

3. 서버는  S3로부터 파일을 가져옵니다.

const AWS = require('aws-sdk')

const confg = {
  accessKeyId: '',
  scretAccessKey: '',
  region: '',
  signatureVersion: 'v4',
};

AWS.config.update(config);
const S3 = new AWS.S3();

function getObjectFromS3(key_name) {
  return new Promise((resolve, reject) => {
    S3.getObject({ Bucket: '', Key: key_name }, (err, data) => {
      if (err) reject(err);
      else resolve(data);
    })
  });
}

 

getObjectFromS3를 이용하면 쉽게 파일을 읽어올 수 있습니다.

자, 지금부터가 집중이 필요합니다.

불러온 데이터는 JSON 형태인데

파일은 Body에 Buffer형태로 따라옵니다.

 

이, Buffer를 어떤식으로 클라이언트로 반환해줄건지

이걸 받으려면 클라이언트는 어떻게 해야하는지

주목해야합니다.

 

다시, 돌아가 클라이언트에서 파일을

어떻게 요청해야되는지 살펴봅시다.

 

4. 클라이언트에서 서버에 특정 파일 요청하기

const requestPrivateFile = () => {
  axios.post(url, {}, { responseType: 'arrayBuffer' })
  .then(resp => {
    const { data } = resp;
    console.log(data);
    ...
  });
}

 

자, 일반적인 API요청과 다르게  responseType으로 arrayBuffer을 지정해주었습니다.

이걸 놓치면 백날 삽질해도 소용없습니다.

 

서버에서도 그러면 값을 맞춰서 반환해줘야겠죠?

 

5. 서버에서 불러온 파일 반환해주기

const getPrivateFile = async (req, res) => {
  ...
  
  const file = await getObjectFromKey('something.pdf');
  
  res.writeHead(200, [ 
    ['Content-Type', 'application/pdf'], //  다른 형식의 파일이면 알맞는 mime/type을 지정해주세요.
  ]);
  res.end(Buffer.from(file.Body, 'base64'));
}

sendFile이나 send 등이 아니라 위와 같은 방식으로

파일을 리턴해주게됩니다.

 

6. 자, 그러면 파일을 받아서 한번 다운로드해볼까요?

const requestPrivateFile = () => {
  axios.post(url, {}, { responseType: 'arrayBuffer' })
  .then(resp => {
    const { data } = resp;

    downloadFile(data, 'something.pdf');
  });
}

function downloadFile(buffer, filename) {
  const blob = new Blob([buffer], { type: 'application/pdf' });
  const url = window.URL.createObjectURL(blob);
  
  const a = document.createElement('a');
  a.download = filename; // download될때의 파일명을 지정해줍니다.
  a.href = url;
  
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a); // 더 이상 필요없으므로 삭제
}

 

자, 여기까지 "서버로부터 buffer 형식으로 파일 전송받아 처리하기"를 해보았습니다.

알고나면 간단하지만 모를때는 조각조각 흩어져있는

토막지식들로인해 어려움을 주는 사항이었습니다...

 

여러가지 상황에 응용이 가능하니 알아두면 좋을것같습니다.

728x90
반응형