top pageへ.

Programming Room.

Google Cloud Tips.

GCS Tips.

CORS設定.2019/11/13

 XML APIを使用する際に必要となる、CORS設定方法の説明です。


おしながき

概要.

 ブラウザでajaxを使用する場合、Cross Origin Resource Sharingポリシーを解決する必要があります。
 「クロスオリジン リソース シェアリング(CORS)」ページの「Cloud Storage CORS のサポート」の章の注意書きに説明されているとおりで、XML APIではバケットのCORS設定が有効です。初期状態では何も設定されていませんので、一切のCORSアクセスが拒否されます。

 設定/取得の方法は「クロスオリジン リソース シェアリング(CORS)の構成」ページに説明されているとおりです。
 gsutilの場合、gsutil自身のヘルプにはcorsコマンドは出てきませんが、公式ドキュメントの説明どおりに使えます。
 また現在はGCPコンソールからの設定・確認はできません。ちょっと不便です。


必要な設定内容.

 設定項目は4つしかないのですが、落とし穴があったりします。

項目 説明
origin アクセス元のオリジン。
スキーマ、ホスト、(指定のある場合)ポートのすべてが一致する必要があります。
responseHeader ほとんど説明がなくて何を設定すればいいのか解り難いのですが、使用する可能性のあるプリフライトの原因となるヘッダを設定するようです。
実際に私が設定したのは、右の2つのみです : "Content-Type", "Authorization"
method 使用するメソッドを設定します。"OPTIONS"メソッドは書かなくても使えます。
オブジェクトのアップロード/ダウンロードのみなら、以下の3つの設定で事足ります。
"GET" : ダウンロードなどでもそのまま使用したいので一応。
"POST" : JSON APIでアップロードに使用します。
"PUT" : XML APIでのアップロードに使用します。
maxAgeSeconds プリフライトのOPTIONSメソッドの有効期間。この期間内なら、再リクエストした場合にプリフライトが省略されるようです。
適当に秒単位で指定します。

 CORSポリシーをパスするためには、以下の2つをresponseHeaderに指定する必要がありました。Googleの公式ドキュメントには、これらにのヘッダが必要になる理由について、説明が見当たりません。以下は調べた範囲での私の解釈です。

ヘッダ名 内容
Content-Type このヘッダは勝手にブラウザが付加するようです。
CORSではContent-Typeヘッダの値が"text/plain", "application/x-www-form-urlencoded", "multipart/form-data"以外の場合はプリフライトが行われます。
XML APIでPUTで送信する場合、マルチパートではなくファイルそのままなので、これらに該当しません。そのためContent-Typeヘッダも指定が必要になるようです。
Authorization 非公開オブジェクトへのアクセスを行うため、アクセストークンを送るのに使用します。
Authorizationヘッダがあるだけでプリフライトが行われるので、指定が必要になるようです。
署名付きURLを使用する場合は、Authorizationヘッダは付けないので、指定しなくても構いません。指定していても問題ありません。

クライアントライブラリでの設定.

 GAE/GCEのアプリケーションから設定するなら、クライアントライブラリを使用するのが便利です。以下のクラス/メソッドを使用します。APIリファレンスも参照ください。

パッケージ クラス メソッド 説明
com.google.cloud.storage Cors バケットのCORS設定を格納します。
Cors.Builder バケットのCORS設定を作成するためのビルダーです。
Cors.Origin CORS設定のオリジン(メソッド、ホスト、ポート)を表すクラスです。
BucketInfo.Builder setCors バケットのメタデータにCORS設定を行います。
Storage update バケットのメタデータを更新します。

 クライアントライブラリを使用したCORS設定のサンプルです。
 origin、method、responseHeaderはHashSetを使用していますが、これらは複数の値を指定可能のためです。下記のサンプルではoriginは1つしか指定していませんが、これも複数指定可能です。
 またCorsクラスのインスタンス自身もHashSetのインスタンスにセットしていることからわかるように、バケットには複数セットの設定を行うことが可能です。

import com.google.cloud.storage.BucketInfo;
import com.google.cloud.storage.Cors;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

class SampleCors {
    // Storageクラスのインスタンスを取得
    private Storage storageInstance = StorageOptions.getDefaultInstance().getService();

    public void setCors(String bucketname, String origin) {
        // origin
        HashSet<Cors.Origin> origins = new HashSet<Cors.Origin>();
        origins.add(Cors.Origin.of(origin));
        // method
        HashSet<HttpMethod> methods = new HashSet<HttpMethod>();
        methods.add(HttpMethod.GET);
        methods.add(HttpMethod.POST);
        methods.add(HttpMethod.PUT);
        // responseHeader
        HashSet<String> headers = new HashSet<String>();
        headers.add("Content-type");
        headers.add("Authorization");

        // ビルダーを生成
        Cors.Builder corsbuilder = Cors.newBuilder()
         .setOrigins(origins)
         .setMethods(methods)
         .setResponseHeaders(headers)
         .setMaxAgeSeconds(Integer.valueOf(600));    // maxAgeSecondsは10分(=600秒)に設定
        // バケットのメタデータにCORSを設定
        HashSet<Cors> corsinfos = new HashSet<Cors>();
        corsinfos.add(corsbuilder.build());
        BucketInfo.Builder infobuilder = BucketInfo.newBuilder(bucketname).setCors(corsinfos);

        // バケットのメタデータを更新
        storageInstance.update(infobuilder.build());
    }
}

▲page top.
Copyright 2005-2023, yosshie.