以前のバンドル サービス用の Blobstore API の概要

Blobstore API を使用すると、blob と呼ばれるデータ オブジェクトをアプリケーションで提供できるようになります。blob は、Datastore サービスのオブジェクトに許可されているサイズよりはるかに大きいサイズのオブジェクトです。blob は、動画や画像などのサイズの大きいファイルを提供する場合や、ユーザーがサイズの大きいデータファイルをアップロードする場合に便利です。blob は HTTP リクエストでファイルをアップロードすることによって作成されます。通常アプリケーションでこの処理を行うには、ファイル アップロード用のフィールドを含むフォームをユーザーに提示します。フォームが送信されると、Blobstore によってファイルの内容から blob が作成され、blob への不透明な参照(blob キー)が返されます。このキーは後で blob を提供するときに使用できます。アプリケーションは、ユーザー リクエストに応じて完全な blob 値を提供でき、あるいはファイルに似たストリーミング インターフェースを使用して、値を直接読み取ることができます。

Blobstore を導入する

App Engine には Blobstore サービスが含まれています。このサービスを利用すると、アプリケーションでデータ オブジェクトを提供できます。制限は 1 回の HTTP 接続でアップロードまたはダウンロードできるデータ量のみです。これらのオブジェクトを Blobstore 値または blob と呼びます。Blobstore 値はリクエスト ハンドラからのレスポンスとして提供され、ウェブフォームを通じたアップロード データとして作成されます。blob データは、アプリケーションで直接作成されるのではなく、送信されたウェブフォームや他の HTTP POST リクエストによって間接的に作成されます。Blobstore API を使用すると、Blobstore 値をユーザーに送信することや、ファイルに似たストリームでアプリケーションから Blobstore 値にアクセスできます。

アプリケーションで Blobstore 値のアップロードをユーザーに促すには、ファイル アップロード用のフィールドを含むウェブフォームを提示します。アプリケーションは、Blobstore API を呼び出してフォームのアクション URL を生成します。ユーザーのブラウザは、生成された URL を通じてファイルを Blobstore に直接アップロードします。次に、Blobstore は blob を保存し、blob キーが含まれるようにリクエストを書き換えて、アプリケーションのパスに渡します。そのパスにはアプリケーションのリクエスト ハンドラがあり、そこで追加のフォーム処理を行うことができます。

blob を提供するには、アプリケーションで送信レスポンスにヘッダーを設定します。このレスポンスは App Engine で blob 値に置き換えられます。

作成した blob は変更できませんが、削除することはできます。各 blob には対応する blob 情報レコードがあり、データストアに保存されています。blob 情報レコードを参照すると、作成日時やコンテンツ タイプなどの blob の詳細がわかります。blob キーを使用して blob 情報レコードをフェッチし、そのプロパティへのクエリができます。

アプリケーションでは API を呼び出して Blobstore 値を読み取れますが、一度に読み取れるサイズは制限されています。制限サイズは API の戻り値の最大サイズで 32 MB より少し小さい値です。Python では定数 google.appengine.ext.blobstore.MAX_BLOB_FETCH_SIZE で表されます。アプリケーションでは、ユーザーがアップロードしたファイルを使用する以外の方法で Blobstore の値を作成または変更できません。

Blobstore を使用する

Blobstore を使用すると、ユーザーからアップロードされるサイズの大きなファイルをアプリケーションで受け取ることや提供することができます。アップロードされたファイルは blob と呼ばれます。アプリケーションが直接 blob にアクセスすることはありません。代わりに、( BlobInfo クラスで表される)Datastore の blob 情報エンティティを介して blob を操作します。

ユーザーは 1 つ以上のファイル入力フィールドを含む HTML フォームを送信して blob を作成します。アプリケーションは、このフォームの宛先(アクション)として blobstore.create_upload_url() を設定します。 この関数には、アプリケーションのハンドラの URL パスを渡します。ユーザーがフォームを送信すると、指定されたファイルがユーザーのブラウザから Blobstore に直接アップロードされます。Blobstore はユーザーのリクエストを書き換え、アップロードされたファイルデータを保存します。その際、アップロードされたファイルデータを 1 つ以上の対応する blob キーで置き換えます。その後、書き換えたリクエストを、blobstore.create_upload_url()に指定された URL パスにあるハンドラに渡します。

このハンドラは、blob キーに基づいて追加の処理を行えます。

アプリケーションは、Blobstore 値の一部を読み取るために ファイルに似たストリーミング インターフェースを使用します。BlobReader クラスをご覧ください。

blob をアップロードする

blob を作成してアップロードする手順は次のとおりです。

1. アップロード URL を作成する

blobstore.create_upload_url()を呼び出して、ユーザーが記入するフォームのアップロード URL を作成し、そのフォームの POST が完了したときに読み込むアプリケーション パスを渡します。

upload_url = blobstore.create_upload_url("/upload_photo")

非同期バージョンの create_upload_url_async() があります。このバージョンでは、Blobstore がアップロード URL を生成している間も、アプリケーション コードを実行し続けることができます。

2. アップロード フォームを作成する

フォームにはファイル アップロード用のフィールドを含め、フォームの enctypemultipart/form-data と設定する必要があります。ユーザーがフォームを送信すると、Blobstore API が POST を処理し、blob を作成します。この API はさらに、blob の情報レコードを作成してデータストアに保存し、指定されたパスにあるアプリケーションに、blob キーに書き換えたリクエストを渡します。

フォームのページは Content-Typetext/html; charset=utf-8 を指定して提供する必要があります。そうしないと、ASCII 以外の文字を使用したファイル名が誤って解釈されます。
Python 3 用 Blobstore は webapp を使用しないため、独自の Content-Type を設定することで、ウェブ フレームワークがデフォルトのコンテンツ タイプを設定したり、App Engine がこれを推測されたタイプに設定したりしないようにします。

サーバーレス NEG を使用するグローバル外部アプリケーション ロードバランサを使用して、blobstore.create_upload_url 呼び出しから返された /_ah/upload/ URL に送信されたアップロード リクエストを処理することはできません。代わりに、これらのアップロード リクエストを App Engine サービスに直接ルーティングする必要があります。これを行うには、appspot.com ドメインまたは App Engine サービスに直接マッピングされたカスタム ドメインを使用します。

3. アップロード ハンドラを実装する

このハンドラでは、blob キーとともにアプリケーションのデータモデルの残りの部分を保存できます。blob キー自体には、Datastore の blob 情報エンティティから引き続きアクセスできます。ユーザーがフォームを送信し、ハンドラが呼び出された時点で、blob はすでに保存され、blob 情報が Datastore に追加されていることに注意してください。アプリケーションに blob を保持しない場合は、すぐに blob を削除して blob が孤立しないようにしてください。

すべての Flask アプリの場合、BlobstoreUploadHandler クラスのメソッドに対するすべての呼び出しでは request.environ dictionary が必要です(flask モジュールからインポートされたリクエスト)。ウェブ フレームワークを備えていない WSGI アプリの場合は、get_uploads() メソッドで environ パラメータを使用します。 ユーザーのリクエストを書き換えるとき、Blobstore はアップロードされたファイルの MIME パーツを空にして、blob キーを MIME パーツのヘッダーとして追加します。他のすべてのフォーム フィールドとパーツは保持され、アップロード ハンドラに渡されます。コンテンツ タイプを指定していない場合、Blobstore はファイル拡張子から推定を試みます。コンテンツ タイプを判断できない場合は、新しく作成された blob にコンテンツ タイプ application/octet-stream を割り当てます。

blob を提供する

blob を提供するには、blob のダウンロード ハンドラをパスとしてアプリケーションに含める必要があります。 このアプリケーションは、送信レスポンスにヘッダーを設定して blob を提供します。Flask を使用する場合、BlobstoreDownloadHandler クラスには request.environ 辞書が必要です(リクエストは flask モジュールからインポートされます)。ウェブ フレームワークを使用しない WSGI アプリの場合は、send_blob() メソッドで environ パラメータを使用します。

blob は、任意のアプリケーション URL から提供できます。アプリケーションで blob を提供するには、blob キーを含むレスポンスに特別なヘッダーを配置します。App Engine はレスポンスの本文を blob のコンテンツに置き換えます。

blob バイトの範囲

Blobstore は、リクエストへのレスポンスとして、サイズの大きな値全体ではなく値の一部の提供をサポートしています。値の一部を提供するには、送信レスポンスに X-AppEngine-BlobRange ヘッダーを含めます。その値は標準的な HTTP バイト範囲とします。バイト番号は 0 から始まります。X-AppEngine-BlobRange を空にすると、API は範囲ヘッダーを無視して blob 全体を提供します。範囲の例を以下に示します。

  • 0-499: 値の最初の 500 バイト(0~499 バイト目まで)を提供します。
  • 500-999: 501 バイト目から始まる 500 バイトを提供します。
  • 500-: 501 バイト目から値の最後までのすべてのバイトを提供します。
  • -500: 値の最後の 500 バイトを提供します。

Blobstore 値に対して有効なバイト範囲が指定されている場合、Blobstore は 206 Partial Content ステータス コードとリクエストされたバイト範囲をクライアントに送信します。範囲が有効でなければ、Blobstore は 416 Requested Range Not Satisfiable を送信します。

Blobstore では、重複の有無にかかわらず、1 回のリクエストで複数のバイト範囲の指定(100-199,200-299 など)を行うことはできません。

サンプル アプリケーションを完成させる

Python 3 用の Blobstore API ガイドで Flask アプリの例をご覧ください。

Blobstore で Images サービスを使用する

Images サービスでは、変換のソースとして Blobstore 値を使用できます。Blobstore 値の最大サイズと同サイズのソース画像を使用できます。Images サービスで変換後の画像がアプリケーションに返されるので、そのサイズは 32 MB より小さくなければなりません。これは、ユーザーがアップロードしたサイズの大きな写真のサムネイル画像を作成する場合に便利です。Images サービスで Blobstore 値を使用する方法については、 Images サービスのドキュメントをご覧ください。

Cloud Storage で Blobstore API を使用する

Blobstore API を使用して Blobstore ではなく Cloud Storage に blob を保存できます。Cloud Storage のドキュメントの説明に従ってバケットを設定し、そのバケットとファイル名を blobstore.create_upload_url gs_bucket_name パラメータに指定する必要があります。

アップロード ハンドラで、必要な FileInfo メタデータを処理し、あとで blob の取得で必要になる Cloud Storage のファイル名を明示的に格納する必要があります。

Blobstore API を使用して Cloud Storage オブジェクトを提供することもできます。

最新のオブジェクト ストレージ ソリューションが必要な場合は、App Engine Blobstore から Cloud Storage への移行を検討してください。

BlobReader を使用する

アプリケーションは、Python の file オブジェクトと同様のインターフェースを使用して Blobstore 値からデータを読み取ることができます。このインターフェースでは、任意のバイト位置で値の読み取りを開始できます。また、1 つのサービス呼び出しのレスポンスにサイズ制限があったとしても、アプリケーションが値全体にアクセスできるように、複数のサービス呼び出しとバッファリングを使用します。

BlobReader クラスは、コンストラクタへの引数として次の 3 つのいずれかの値を取ることができます。

このオブジェクトは、値を読み取るために使い慣れたファイル メソッドを実装しています。ただし、アプリケーションは Blobstore 値を変更できません。つまり、書き込むためのファイル メソッドは実装されていません。

# Instantiate a BlobReader for a given Blobstore blob_key.
blob_reader = blobstore.BlobReader(blob_key)

# Instantiate a BlobReader for a given Blobstore blob_key, setting the
# buffer size to 1 MB.
blob_reader = blobstore.BlobReader(blob_key, buffer_size=1048576)

# Instantiate a BlobReader for a given Blobstore blob_key, setting the
# initial read position.
blob_reader = blobstore.BlobReader(blob_key, position=0)

# Read the entire value into memory. This may take a while depending
# on the size of the value and the size of the read buffer, and is not
# recommended for large values.
blob_reader_data = blob_reader.read()

# Write the contents to the response.
self.response.headers["Content-Type"] = "text/plain"
self.response.write(blob_reader_data)

# Set the read position back to 0, then read and write 3 bytes.
blob_reader.seek(0)
blob_reader_data = blob_reader.read(3)
self.response.write(blob_reader_data)
self.response.write("\n")

# Set the read position back to 0, then read and write one line (up to
# and including a '\n' character) at a time.
blob_reader.seek(0)
for line in blob_reader:
    self.response.write(line)

非同期リクエストを行う

アプリケーションは、バックグラウンドで動作するいくつかの Blobstore 関数を呼び出すことができます。アプリケーションが他の処理を実行している最中に、Blobstore はリクエストを実行できます。このリクエストを行うには、アプリケーションから非同期関数を呼び出します。この関数はすぐに RPC オブジェクトを返し、このオブジェクトがリクエストを表します。アプリケーションでリクエストの結果が必要な場合は、RPC オブジェクトの get_result() メソッドを呼び出します。

アプリケーションが get_result() を呼び出したときにサービスがリクエストを完了していない場合、メソッドはリクエストが完了する(または、期限切れになるかエラーが発生する)まで待機します。メソッドは結果オブジェクトを返します。リクエストの実行中にエラーが発生した場合は、例外を発生させます。たとえば、次のコード スニペットは、

upload_url = blobstore.create_upload_url('/upload')
slow_operation()
self.response.out.write("""<form action="%s" method="POST"
                           enctype="multipart/form-data">""" % upload_url)

以下のようになります。

upload_url_rpc = blobstore.create_upload_url_async('/upload')
slow_operation()
upload_url = upload_url_rpc.get_result()
self.response.out.write("""<form action="%s" method="POST"
                           enctype="multipart/form-data">""" % upload_url)

この例では、Blobstore がアップロード URL を生成すると同時に、アプリケーションが slow_operation() コードを実行します。

割り当てと上限

Blobstore 値に使用する領域は、保存データ(課金対象)の割り当て量の計算対象になります。Datastore の blob 情報エンティティは Datastore 関連の制限に対してカウントされます。なお、Cloud Storage は従量課金サービスであり、Cloud Storage の価格表に従って課金されることに注意してください。

システム全体の安全上の割り当て量について詳しくは、割り当てをご覧ください。

Blobstore の使用については特に、システム全体の安全上の割り当て量に加えて次の制限が適用されます。

  • アプリケーションからの API 呼び出し 1 回で読み取ることのできる Blobstore データの最大サイズは 32 MB です。
  • 1 つのフォームの POST でアップロードできるファイルの最大数は 500 です。