본문 바로가기
Web/Backend

[GCS] 구글 클라우드 스토리지(GCS)로 파일 업로드 후 접근 URL 생성하기

by r4bb1t 2020. 6. 1.
반응형

결과물 미리보기

1. 새 프로젝트 및 버킷 만들기 |

 

구글 클라우드 스토리지에서 새 버킷을 만들어 준다.

나는 대충 이렇게 했다.

아래부터는 이 문서를 93.5% 정도 따라하는 내용이다😁

 

2. 초기 설정 |

 

$ npm init -y
$ npx tsc --init
$ npm install -S typescript @google-cloud/storage dotenv express multer pug
$ npm install -D @types/express @types/node nodemon

 

ts를 쓸 것이기 때문에 typescript도 설치해 준다.

 

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "./dist",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*.ts"]
}

 

package.json과 같은 위치에 tsconfig.json 만들어서 위 내용 넣어주고..

 

GCLOUD_STORAGE_BUCKET=your-bucket
GOOGLE_APPLICATION_CREDENTIALS=path/to/your/key.json

 

같은 곳에 .env 파일도 만들어서 버킷 이름과 만든 서비스 계정 키의 위치를 넣어준다.

 

import { format } from "util";
import express from "express";
import Multer from "multer";
import bodyParser from "body-parser";
import { Storage as GCStorage } from "@google-cloud/storage";
import dotenv from "dotenv";
dotenv.config();

 

필요한 것들을 import해주고... dotenv.config()로 .env파일을 process.env에 불러온다.

Storage를 GCStorage라는 이름으로 불러오는 이유는 typescript에 이미 Storage라는 친구가 있어서...

 

3. 애플리케이션 코드 |

 

doctype html
html(lang="en")
  head
    title Static Files
    meta(charset='utf-8')
  body
    form(method="POST", action="/upload", enctype="multipart/form-data")
      input(type="file", name="file")
      input(type="submit")

 

일단 view 폴더 안에 form.pug 파일을 만들어 위 내용을 넣어준다... 이 친구의 역할은 그냥 아래처럼 업로드 form을 보여주고 제출하면 /upload에 POST해주는 것...

 

const storage = new GCStorage();

const app = express();
app.set("view engine", "pug");
app.use(bodyParser.json());

const multer = Multer({
  storage: Multer.memoryStorage(),
  limits: {
    fileSize: 5 * 1024 * 1024, // 5mb
  },
});


const bucket = storage.bucket(process.env.GCLOUD_STORAGE_BUCKET);

app.get("/", (req, res) => {
  res.render("form.pug");
});


app.post("/upload", multer.single("file"), (req, res, next) => {
  if (!req.file) {
    res.status(400).send("No file uploaded.");
    return;
  }

  
  const blob = bucket.file(req.file.originalname);
  const blobStream = blob.createWriteStream();

  blobStream.on("error", (err) => {
    next(err);
  });

  blobStream.on("finish", () => {
      
    const publicUrl = format(`https://storage.googleapis.com/${bucket.name}/${blob.name}`);
    res.status(200).send(publicUrl);
  });

  blobStream.end(req.file.buffer);
});

const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
  console.log("Press Ctrl+C to quit.");
});

 

.env에 설정해둔 PORT 혹은 디폴트 8080 포트에서 실행될 것이다.

http://localhost:8080/은 이미지 업로드 폼 form.pug 를 보여주고, /upload URL에 POST 요청이 들어오면 받은 body의 객체를 multer.single('file')이 req.file로 변환해준다.

 

 

버킷에 개체들이 잘 업로드되는 걸 알 수 있다.

 

 

그리고 표시되는 publicURL에 들어가면 이미지가 떠야 하는데

 

 

이렇게 뜰 것이다. 버킷이 공개 액세스가 안 돼서 그렇다.  버킷에 균일한 버킷 수준 액세스를 사용 설정한 경우 버킷 자체를 공개 액세스로 만들 수는 없고, 대신 버킷의 모든 객체에 공개 읽기 권한을 부여하거나 Signed URL을 사용하면 된다.

전에 번역한 글에서는 Signed URL을 사용했는데, 이 글에서는 모든 객체에 공개 읽기 권한을 줄 것이다.

 

 

나는 이미 공개 읽기 권한을 줘서 ⚠이 버킷은 공개 상태이며... 메시지가 뜨고 있다. 여기서 구성원 추가를 눌러서

 

 

allUsers에 저장소 개체 뷰어 권한을 준다. 그 후 다시 publicURL에 들어가면

 

 

이런 식으로 이미지가 잘 나온다!

유용하게 이용할 수 있겠다.

반응형

댓글