- この記事は、Google Playゲームサービスに関する記事を和訳したものです。
- 原文: Uploading Images
- 元記事のライセンスは CC-BYで、この和訳記事のライセンスは CC-BYです。
- 自己責任でご利用ください。
- 和訳した時期は 2019年7月ころです。
Playゲームサービス Publishing APIは、ゲームリソースの画像をアップロードできるようにします。
アップロードオプション
Playゲームサービス Publishing APIは、特定のタイプのバイナリデータ、あるいは、メディアをアップロードできるようにします。 アップロードすることができるデータの具体的な特性は、メディアのアップロードをサポートする任意のメソッドのリファレンスページに指定されています:
- アップロードファイルの最大サイズ: このメソッドを用いて格納することができるデータの最大量。
- 受け入れられるメディアの MIMEタイプ: このメソッドを使用して格納することができるバイナリデータのタイプ。
以下のいずれかの方法でアップロードのリクエストをすることができます。
uploadType
リクエストパラメータを用いて使用するメソッドを指定します。
-
シンプルアップロード:
uploadType=media
。 例えば 5MB以下といった、より小さなファイルの素早い転送のために。 -
マルチパートアップロード:
uploadType=multipart
。 より小さなファイルおよびメタデータの素早い転送のために; 単一のリクエストにて、ファイルを、それを記述するメタデータとともに転送します。 -
再開可能なアップロード:
uploadType=resumable
。 信頼できる転送のために、それは、特により大きなファイルを用いるときに重要です。 このメソッドを用いてセッション開始リクエストを使用します、それは、必要に応じてメタデータを含むことができます。 これは、アップロードごとに 1つの追加の HTTPリクエストのコストでより小さなファイルのために動作するので、ほとんどのアプリケーションにとって使用するための良い戦略です。
メディアをアップロードするとき、特別な URIを使用します。 実際には、メディアのアップロードをサポートするメソッドは、2つの URIエンドポイントを持っています:
-
/upload URI、メディア用。
アップロードエンドポイントの形式は、“/upload” 接頭辞を用いた標準的なリソース URIです。
メディアデータ自身を転送するときにこの URIを使用します。
例えば:
POST /upload/games/v1configuration/images/resourceId/imageType/imageType
-
標準的なリソース URI、メタデータ用。
もしリソースが任意のデータフィールドを含んでいるならば、それらのフィールドはアップロードされたファイルを記述したメタデータを格納するために使用されます。
メタデータの値を作成あるいは更新するとき、この URIを使用することができます。
例えば:
POST /games/v1configuration/images/resourceId/imageType/imageType
シンプルアップロード
ファイルをアップロードするための最も簡単なメソッドは、シンプルアップロードのリクエストをすることです。 このオプションは次のときに良い選択です:
- ファイルが、接続が失敗した場合にも、その全体を再びアップロードするために十分に小さいとき。
- 送信するためのメタデータがないとき。 もし、別々のリクエストにてこのリソースのためのメタデータを送信することを計画しているならば、あるいは、もし、利用可能なメタデータやサポートされているメタデータがなければ、これが真であるかもしれません。
シンプルアップロードを使用するには、メソッドの /upload URIに POST
あるいは PUT
リクエストをし、クエリパラメータ uploadType=media
を追加します。
例えば:
POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=media
シンプルアップロードのリクエストをするときに使用するための HTTPヘッダは、次を含みます:
-
Content-Type
。 API referenceにて指定された、メソッドの受け入れられるアップロードメディアのデータタイプのいずれかをセットします。 -
Content-Length
。 アップロードしているバイト数をセットします。 もし chunked transfer encodingを使用しているならば、必要ありません。
例: シンプルアップロード
次の例では、Playゲームサービス Publishing API用の、シンプルアップロードのリクエストの使用を示しています。
POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=media HTTP/1.1 Host: www.googleapis.com Content-Type: image/png Content-Length: number_of_bytes_in_file Authorization: Bearer your_auth_token PNG data
もしリクエストが成功したならば、サーバは任意のメタデータとともに HTTP 200 OK
ステータスコードを返します:
HTTP/1.1 200 Content-Type: application/json {
"kind": "gamesConfiguration#imageConfiguration",
"url": string,
"resourceId": string,
"imageType": string
}
マルチパートアップロード
もしアップロードするためのデータとともに送信したいメタデータがあるならば、単一の multipart/related
リクエストをすることができます。
これは、送信しているデータが、もし接続が失敗した場合に、その全体を再びアップロードするために十分に小さい場合に、良い選択です。
マルチパートアップロードを使用するには、メソッドの /upload URIに POST
あるいは PUT
リクエストをし、クエリパラメータ uploadType=multipart
を追加します、例えば:
POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=multipart
マルチパートのアップロードリクエストをするときに使用するトップレベルの HTTPヘッダは、次のとおりです:
-
Content-Type
。 multipart/relatedをセットし、リクエストの部分を識別するために使用している境界文字列を含んでいます。 -
Content-Length
。 リクエストボディの総バイト数をセットします。 リクエストのメディア部分は、このメソッドに指定した最大ファイルサイズよりも小さくなければなりません。
リクエストのボディは、multipart/related
コンテンツタイプ [RFC2387] としてフォーマットされていて、正確に 2つの部分を含んでいます。
部分は境界文字列によって識別され、境界文字列の後には 2つのハイフンが続きます。
マルチパートリクエストのそれぞれの部分は、追加の Content-Type
ヘッダが必要です:
-
メタデータ部分:
最初に来なければなりません、そして、
Content-Type
は受け入れられるメタデータの形式のいずれかと一致しなければなりません。 -
メディア部分:
2番目に来なければなりません、そして、
Content-Type
はメソッドの受け入れられるメディア MIMEタイプのいずれかと一致しなければなりません。
それぞれのメソッドの受け入れられる、メディアの MIMEタイプのリスト、および、アップロードされたファイルのサイズ制限については、API referenceを参照してください。
備考:
関連するデータをアップロードすることなく、メタデータの部分のみを作成あるいは更新するには、単純に、標準的なリソースのエンドポイントに POST
あるいは PUT
リクエストを送信します:
https://www.googleapis.com/games/v1configuration/images/resourceId/imageType/imageType
例: マルチパートアップロード
次の例では、Playゲームサービス Publishing API用の、マルチパートアップロードのリクエストを示しています。
POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=multipart HTTP/1.1 Host: www.googleapis.com Authorization: Bearer your_auth_token Content-Type: multipart/related; boundary=foo_bar_baz Content-Length: number_of_bytes_in_entire_request_body --foo_bar_baz Content-Type: application/json; charset=UTF-8 {
"kind": "gamesConfiguration#imageConfiguration",
"url": string,
"resourceId": string,
"imageType": string
} --foo_bar_baz Content-Type: image/png PNG data --foo_bar_baz--
もしリクエストが成功したならば、サーバは任意のメタデータとともに HTTP 200 OK
ステータスコードを返します:
HTTP/1.1 200 Content-Type: application/json {
"kind": "gamesConfiguration#imageConfiguration",
"url": string,
"resourceId": string,
"imageType": string
}
再開可能なアップロード
データファイルをより確実にアップロードするために、再開可能なアップロードプロトコルを使用することができます。 このプロトコルは、通信障害がデータのフローを中断させた後、アップロード操作を再開できるようにします。 もし、大きなファイルを転送していて、ネットワークの中断あるいは幾つかの他の伝送障害の可能性が高いならば、例えば、モバイルクライアントのアプリからアップロードしているときに、特に有用です。 さらには、ネットワーク障害の時、大きなファイルのアップロードを最初から再スタートする必要がないので、あなたの帯域幅の使用を減らすことができます。
再開可能なアップロードを使用する手順は次の通りです:
- 再開可能なセッションを開始する。 アップロード URIに、もしあればメタデータを含む最初のリクエストをします。
- 再開可能なセッションの URIを保存する。 最初のリクエストのレスポンスにて返されたセッションの URIを保存します; このセッションにて、残りのリクエストのためにそれを使用するでしょう。
- ファイルをアップロードする。 再開可能なセッションの URIにメディアファイルを送信します。
また、再開可能なアップロードを使用するアプリは、中断されたアップロードを再開するためのコードを持っている必要があります。 もしアップロードが中断されたならば、正常に受信されたデータの量を調べ、それから、その時点から開始するアップロードを再開します。
備考: アップロード URIは一週間後に失効します。
Step 1: 再開可能なセッションを開始する
再開可能なアップロードを開始するには、メソッドの /upload URIに POST
あるいは PUT
リクエストをし、クエリパラメータ uploadType=resumable
を追加します、例えば:
POST https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable
この開始リクエストでは、ボディは空あるいはメタデータのみを含みます; 後続のリクエストにて、アップロードしたいファイルの実際のコンテンツを転送します。
Use the following HTTP headers with the initial request: 最初のリクエストでは次の HTTPヘッダを使用します:
-
X-Upload-Content-Type
。 後続のリクエストにて転送されるアップロードデータのメディア MIMEタイプをセットします。 -
X-Upload-Content-Length
。 後続のリクエストにて転送されるアップロードデータのバイト数をセットします。 もし長さがこのリクエストの時点で不明ならば、このヘッダを省略することができます。 -
もしメタデータを提供するならば:
Content-Type
。 メタデータのデータタイプに合わせてセットします。 -
Content-Length
。 この最初のリクエストのボディで提供されるバイト数をセットします。 もし chunked transfer encodingを使用しているならば、必要ありません。
それぞれのメソッドの受け入れられる、メディアの MIMEタイプのリスト、および、アップロードされたファイルのサイズ制限については、API referenceを参照してください。
例: 再開可能なセッションの開始のリクエスト
次の例では、Playゲームサービス Publishing APIのために再開可能なセッションを開始する方法を示しています。
POST /upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable HTTP/1.1 Host: www.googleapis.com Authorization: Bearer your_auth_token Content-Length: 38 Content-Type: application/json; charset=UTF-8 X-Upload-Content-Type: image/png X-Upload-Content-Length: 2000000 {
"kind": "gamesConfiguration#imageConfiguration",
"url": string,
"resourceId": string,
"imageType": string
}
備考:
メタデータを伴わない最初の再開可能な更新リクエストでは、リクエストのボディを空にしておき、Content-Length
ヘッダに 0
をセットします。
次のセクションでは、レスポンスを処理する方法について説明します。
Step 2: 再開可能なセッションの URIを保存する
もしセッション開始リクエストが成功したならば、APIサーバは 200 OK
HTTPステータスコードをレスポンスします。
また、それは、あなたの再開可能なセッションの URIを指定する Location
ヘッダを提供します。
Location
ヘッダは、以下の例に示すように、このセッションのために使用される一意のアップロード IDを与える upload_id
クエリパラメータ部分を含んでいます。
例: 再開可能なセッションの開始のレスポンス
Step 1でのリクエストに対するレスポンスは次のとおりです:
HTTP/1.1 200 OK Location: https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2 Content-Length: 0
Location
ヘッダの値は、上記の例のレスポンスに示されるように、実際のファイルアップロードをする、あるいはアップロードステータスをクエリするための HTTPエンドポイントとして使用するセッション URIです。
後続のリクエストのために使用するので、セッションの URIをコピーし保存します。
Step 3: ファイルをアップロードする
ファイルをアップロードするには、前の手順にて取得したアップロード URIに PUT
リクエストを送信します。
アップロードリクエストの形式は次のとおりです:
PUT session_uri
再開可能なファイルアップロードのリクエストをするときに使用するための HTTPヘッダは Content-Length
を含んでいます。
これを、このリクエストにてアップロードしているバイト数にセットします、それは、一般的には、アップロードするファイルのサイズです。
例: 再開可能なファイルアップロードのリクエスト
ここに、現在の例として、全体で 2,000,000バイトの PNGファイルをアップロードするための再開可能なリクエストがあります。
PUT https://www.googleapis.com/upload/games/v1configuration/images/resourceId/imageType/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1 Content-Length: 2000000 Content-Type: image/png bytes 0-1999999
もしリクエストが成功したならば、サーバは、このリソースに関連付けられた任意のメタデータとともに、HTTP 201 Created
をレスポンスします。
もし再開可能なセッションの最初のリクエストが PUT
で、それが、既存のリソースを更新するのであれば、成功レスポンスは、このリソースと関連付けられた任意のメタデータとともに 200 OK
になるでしょう。
もしアップロードリクエストが中断されたならば、あるいは、もしサーバから HTTP 503 Service Unavailable
あるいは他の 5xx
レスポンスを受信したならば、中断されたアップロードを再開するにて概説されている手順に従ってください。
チャンクにてファイルをアップロードする
再開可能なアップロードを用いて、ファイルをチャンクに分割し、それぞれのチャンクを順序通りにアップロードするための一連のリクエストを送信することができます。 これは、追加のリクエストに関連付けられた性能コストがあるため好ましいアプローチではなく、一般的には必要とされません。 しかしながら、任意の単一のリクエストにて転送されるデータの量を減らすために、チャンクを使用する必要があるかもしれません。 個々のリクエストのために一定の制限時間ががあるとき、Google App Engineのリクエストの特定のクラスがそうであるように、これは有用です。 さらには、デフォルトではアップロードの進行状況をサポートしていないレガシーブラウザのために、アップロードの進行状況の表示を提供するようなことをさせます。
中断されたアップロードを再開する
もしアップロードリクエストがレスポンスを受信する前に終了したならば、あるいは、もしサーバから HTTP 503 Service Unavailable
レスポンスを受信したならば、中断されたアップロードを再開する必要があります。
これを行うには:
-
状態をリクエストします。
アップロード URIに空の
PUT
リクエストを発行することによってアップロードの現在のステータスをクエリします。 このリクエストでは、HTTPヘッダは、ファイル内の現在の位置が不明であることを示すContent-Range
ヘッダを含む必要があります。 例えば、合計ファイルの長さが 2,000,000である場合、Content-Range
に*/2000000
をセットします。 もしファイルの完全なサイズを知らなければ、Content-Range
に*/*
をセットします。備考: アップロードが中断された場合だけでなく、チャンク間にステータスをリクエストすることができます。 これは、例えば、レガシーなブラウザにアップロードの進行状況を示したい場合に有用です。
-
アップロードされたバイト数を取得します。
ステータスクエリからのレスポンスを処理します。
サーバは、これまでに受信したバイトを指定するために、そのレスポンス内に
Range
ヘッダを使用します。 例えば、0-299999
のRange
ヘッダは、ファイルの最初の 300,000バイトが受信されたことを示しています。 -
残りのデータをアップロードします。
最後に、今やリクエストを再開する場所を知ったので、残りのデータあるいは現在のチャンクを送信します。
いずれの場合でも、残りのデータを分割されたチャンクとして扱う必要があるので、アップロードを再開するときに
Content-Range
ヘッダを送信する必要があることに注意してください。
例: 中断されたアップロードを再開する
1) アップロードステータスをリクエストします。
次のリクエストは、2,000,000バイトのファイルの現在の位置が不明であることを示すために Content-Range
ヘッダを使用しています。
PUT {session_uri} HTTP/1.1 Content-Length: 0 Content-Range: bytes */2000000
2) レスポンスから、これまでにアップロードされたバイト数を抽出します。
サーバのレスポンスは、これまでにファイルの最初の 43バイトを受信したことを示す Range
ヘッダを使用しています。
再開されるアップロードを開始する場所を決定するために、Range
ヘッダの上限値を使用します。
HTTP/1.1 308 Resume Incomplete Content-Length: 0 Range: 0-42
備考:
アップロードが完了していた場合、ステータスレスポンスは 201 Created
あるいは 200 OK
になる可能性があります。
これは、すべてのバイトがアップロードされた後、クライアントがサーバからのレスポンスを受信する前に接続が壊れた場合に発生する可能性があります。
3) 中断したポイントからのアップロードを再開します。
次のリクエストは、バイト 43から始まるファイルの残りのバイトを送信することによって、アップロードを再開します。
PUT {session_uri} HTTP/1.1 Content-Length: 1999957 Content-Range: bytes 43-1999999/2000000 bytes 43-1999999
ベストプラクティス
メディアをアップロードするとき、エラー処理に関連した幾つかのベストプラクティスに注意することが有用です。
-
接続の中断、あるいは、次のような
5xx
エラーに起因して失敗したアップロードを、再開あるいはリトライします:-
500 Internal Server Error
-
502 Bad Gateway
-
503 Service Unavailable
-
504 Gateway Timeout
-
-
もし、再開あるいはリトライのアップロードをリクエストしたとき任意の
5xx
サーバエラーが返されたならば、指数のバックオフ戦略を使用します。 これらのエラーは、サーバが過負荷になっている場合に発生する可能性があります。 指数のバックオフは、多量のリクエストあるいは大量のネットワークトラフィックの期間中の、この種の問題を軽減することができます。 - 他の種類のリクエストは、指数のバックオフによって処理されるべきではないですが、まだそれらの数をリトライすることができます。 これらのリクエストをリトライするとき、それらをリトライする回数を制限します。 例えば、あなたのコードは、エラーを報告する前に 10回以下に制限することができます。
-
再開可能なアップロードを行っているときの
404 Not Found
エラーを、最初から全体のアップロードをやり直すことによって処理します。
指数のバックオフ
指数のバックオフは、クライアントが、失敗したリクエストを時間の量を増加させながら定期的にリトライするという、ネットワークアプリケーションにとって標準的なエラー処理戦略です。 もし、多量のリクエストあるいは大量のネットワークトラフィックがサーバにエラーを返すことを引き起こすならば、指数のバックオフはこれらのエラーを処理するための良い戦略になるかもしれません。 逆に、無効な認証資格情報、あるいは、ファイルが見つからないエラーといった、ネットワーク量あるいはレスポンス時間とは無関係のエラーを扱うための適切な戦略ではありません。
適切に使用された指数のバックオフは、効率的な帯域幅の使用を増加させ、正常なレスポンスを取得するために必要とされるリクエスト数を減少させ、コンカレントな環境にてリクエストのスループットを最大化させます。
シンプルな指数のバックオフを実装するためのフローは次のとおりです:
- APIにリクエストします。
-
HTTP 503
レスポンスを受信します、それはリクエストをリトライする必要があることを示します。 - 1秒 + random_number_milliseconds 待ち、リクエストをリトライします。
-
HTTP 503
レスポンスを受信します、それはリクエストをリトライする必要があることを示します。 - 2秒 + random_number_milliseconds 待ち、リクエストをリトライします。
-
HTTP 503
レスポンスを受信します、それはリクエストをリトライする必要があることを示します。 - 4秒 + random_number_milliseconds 待ち、リクエストをリトライします。
-
HTTP 503
レスポンスを受信します、それはリクエストをリトライする必要があることを示します。 - 8秒 + random_number_milliseconds 待ち、リクエストをリトライします。
-
HTTP 503
レスポンスを受信します、それはリクエストをリトライする必要があることを示します。 - 16秒 + random_number_milliseconds 待ち、リクエストをリトライします。
- 停止します。 エラーを報告あるいは記録します。
上記のフローにて、random_number_millisecondsは 1000以下のランダムな数のミリ秒です。 これは必要です、なぜなら、小さなランダムの遅延を導入することは、負荷をより均等に分散し、サーバを暴走させる可能性を避けることに役立つからです。 random_number_millisecondsの値は、それぞれの待機の後に再定義されなければなりません。
備考: 待機は、常に (2 ^ n) + random_number_millisecondsです、そこでは、nは初期値が 0に定義された単調に増加する整数です。 整数 nは、それぞれの反復(それぞれのリクエスト)のために 1だけインクリメントされます。
アルゴリズムは nが 5のときに終了するようセットされています。 この上限は、クライアントが無限にリトライすることを防ぎ、リクエストが "an unrecoverable error" とみなされる前に、全体で約 32秒の遅延をもたらします。 リトライの最大数をより大きくすることは、特に長いアップロードが進行中である場合に、良いです; 例えば 1分未満というように、何か合理的にリトライの遅延をキャップしてください。