본문 바로가기

Cloud/GCP

GCS 서명된 URL로 파일 업로드(JavaScript)

배경

웹 애플리케이션에서 파일을 업로드하려면 서버로 파일을 보내야 합니다. 하지만 파일의 용량이 너무 크거나 업로드 트래픽이 급증했을 경우, 백엔드 서버의 메모리가 초과돼서 서버가 다운될 수 있습니다. 이런 경우엔 클라이언트 측에서 하나의 파일을 작게 chunk 해서 여러 번 요청하면 서버의 부담이 줄어들기 때문에 서버에 직접 저장하는 경우엔 효과적입니다. 하지만 GCP와 같은 클라우드 플랫폼을 사용하는 경우, 보통 파일을 버킷에 저장하기 때문에 클라이언트 측에서 버킷으로 직접 업로드를 요청하는 것이 더욱 안전하고 효율적인 방법입니다. 이 글에선 백엔드에서 서명된 URL을 만들고, 이를 클라이언트로 보내서 직접 업로드하는 방법을 다룹니다.


서명된 URL?

URL이 있으면 누구나 해당 버킷에 접근할 수 있는 URL입니다. URL에는 버킷에 대한 권한과 만료 시간 등의 정보가 포함되어 있습니다.


개발 환경

개발 환경은 아래와 같습니다.

  • 저장소: GCP 비공개 버킷
  • 프런트엔드: NextJS
  • 백엔드: NestJS

1. 버킷에 CORS-Rule 적용

버킷에 CORS-Rule을 설정하지 않으면 클라이언트 측에서 요청할 때 오류가 발생하므로 반드시 적용해주어야 합니다.

아래 링크를 참고해서 설정해주세요.

https://sty110357.tistory.com/144

 

2. 백엔드에서 서명된 URL 생성

import { Storage } from '@google-cloud/storage';

async getGcsUploadSignedUrl() {
  const storage = new Storage({ projectId: 'YOUR-PROJECT-ID' });
  const bucket = storage.bucket('YOUR-BUCKET-NAME');
  const file = bucket.file('YOUR-FILE-NAME');
  const urls = await file.getSignedUrl({
    version: 'v4', // 'v4' | 'v2'
    expires: Date.now() + 1000 * 60 * 60, // 1시간
    action: 'write', // write|read|delete|resumable
  });
  return urls[0];
}
  • version: 서명 생성 로직 버전
  • expires: URL 유효 기한
  • action: URL에 부여할 권한

 

3. 프런트에서 서명된 URL 사용

const file = files[0]; // <input type="file" />의 파일
const type = file.type;
// 백엔드로부터 서명된 URL을 가져옵니다.
axios.get(`/api/file/upload`).then(async (res) => {
  // 가져온 서명된 URL에 파일을 전송합니다.
  axios.put(res.data, file, { headers: { 'content-type': type } });
});