※ Papago와 짧은 영어 지식을 동원해서 번역했습니다. 오역한 부분이 있다면 알려주세요😏
브라우저에서 GCS로 파일을 직접 업로드하기 위해 하루 종일 애쓰면서 나는 인터넷이 결과를 설명하는 방법을 통해 좋은 결과를 낼 수 있다는 것을 느꼈다.
배경 |
우리는 app.imerso.com 플랫폼의 파일들을 저장하기 위해 GCS를 쓴다. 하지만, 우리는 자체적인 인증방식을 사용하기 때문에 사용자들에게 구글 연결을 요구하지 않는다. 그래서 승인을 위해 표준 구글 API 클라이언트 라이브러리 자바스크립트를 사용할 수 없다. 대신 우리는 Signed URL을 사용하기로 했다.
해결책 |
업로드는 백엔드에서 승인하고, 파일 전송은 프론트엔드에서 GCS의 API로 직접 전송하여 인증된 사용자만 GCS 버킷에 파일을 업로드할 수 있게 하고 싶었다. 그래서 REST API에 사용자 인증 요청을 하고, REST API는 지정된 파일의 이름 및 Content-Type으로 PUT 요청을 하기 위한 URL에 서명한 후 Signed URL을 프론트엔드로 반환한다.
백엔드 |
우리의 백엔드는 스칼라(Scala)로 작성되어 있으며, Signed URL을 만들기 위해 아래 코드를 사용한다.
// contentType과 objectPath값은 프론트엔드에서 보내야 함
val contentType = "image/png"
val objectPath = "my-favorite-cat-photo.png"
val bucket = "my-cat-bucket"
val storage = StorageOptions.getDefaultInstance.getService
val blob = storage.create(
BlobInfo.newBuilder(bucket, objectPath)
.setContentType(contentType)
.build()
)
// <objectPath> 와 Content-Type "PUT"으로 파일 PUT에 유효한 Signed URL을 만듦. 하루 동안 유효함.
val urlPut = storage.signUrl(blob, 1, TimeUnit.DAYS, SignUrlOption.httpMethod(HttpMethod.PUT), SignUrlOption.withContentType())
GCP 프로젝트의 백엔드를 인증하기 위한 서비스 계정 키를 만들자. json 키를 생성한 후에는 서버의 키를 가리키도록 환경 변수를 설정하자.
GOOGLE_APPLICATION_CREDENTIALS=path/to/service-account/key.json
안 하면 storage.create가 StorageException를 뿜는다. 또 여기서 사용하는 서비스 계정이 "Object Creator" 또는 "Object Admin" 처럼 사용하는 버킷에 대한 올바른 권한을 가지고 있는지 확인하자.
프론트엔드 |
GCS는 GCS에 대해 두 가지 다른 API를 제공한다.
- XML-API
- JSON-API
불행하게도 (작성 당시 기준으로) XML-API만 Signed URL을 지원하기 때문에 XML-API를 쓴다.
아래는 REST-API에서 제공하는 signed Url과 XML-API를 사용하여 파일을 업로드하는 코드이다.
const signedUrl = getSignedUrlFromBackend();
// this can be a file from e.g. <input type="file"/>
const file = getFileToUpload();
const xhr = new XMLHttpRequest();
xhr.open("PUT", signedUrl, true);
xhr.onload = () => {
const status = xhr.status;
if (status === 200) {
alert("File is uploaded");
} else {
alert("Something went wrong!");
}
};
xhr.onerror = () => {
alert("Something went wrong");
};
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);
브라우저에서 이 기능을 실행하려면 백엔드 코드에 지정된 버킷에 올바른 CORS 설정이 있는지 확인해보자. (gsutil로 CORS 설정 확인하기 : gsutil cors get gs://<your-bucket>)
[
{
"maxAgeSeconds": 3600,
"method": ["GET", "HEAD", "PUT"],
"origin": [<http://your-super-awesome-domainz.gov>],
"responseHeader": ["Content-Type", "Access-Control-Allow-Origin"]
}
]
끝이다. 누군가 유용하다고 생각했으면 좋겠다!
'Web > Backend' 카테고리의 다른 글
[GCP] 구글 클라우드 플랫폼에 Nginx로 리액트 프로젝트 배포하기 (2) | 2020.11.29 |
---|---|
[JWT] JSON Web Token (0) | 2020.08.19 |
[GCP] 구글 클라우드 DNS에 도메인 연결하기 (2) | 2020.07.20 |
[GCS] 구글 클라우드 스토리지(GCS)로 파일 업로드 후 접근 URL 생성하기 (3) | 2020.06.01 |
[NodeJS] 소켓을 이용한 간단한 채팅방 만들기 (0) | 2020.04.30 |
댓글