画像をアップロードする



  • この記事は、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ヘッダが必要です:

  1. メタデータ部分: 最初に来なければなりません、そして、Content-Typeは受け入れられるメタデータの形式のいずれかと一致しなければなりません。
  2. メディア部分: 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
}

再開可能なアップロード

データファイルをより確実にアップロードするために、再開可能なアップロードプロトコルを使用することができます。 このプロトコルは、通信障害がデータのフローを中断させた後、アップロード操作を再開できるようにします。 もし、大きなファイルを転送していて、ネットワークの中断あるいは幾つかの他の伝送障害の可能性が高いならば、例えば、モバイルクライアントのアプリからアップロードしているときに、特に有用です。 さらには、ネットワーク障害の時、大きなファイルのアップロードを最初から再スタートする必要がないので、あなたの帯域幅の使用を減らすことができます。

再開可能なアップロードを使用する手順は次の通りです:

  1. 再開可能なセッションを開始する。 アップロード URIに、もしあればメタデータを含む最初のリクエストをします。
  2. 再開可能なセッションの URIを保存する。 最初のリクエストのレスポンスにて返されたセッションの URIを保存します; このセッションにて、残りのリクエストのためにそれを使用するでしょう。
  3. ファイルをアップロードする。 再開可能なセッションの 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のリクエストの特定のクラスがそうであるように、これは有用です。 さらには、デフォルトではアップロードの進行状況をサポートしていないレガシーブラウザのために、アップロードの進行状況の表示を提供するようなことをさせます。

Expand for more info

もしチャンクにてデータをアップロードしているならば、Content-Rangeヘッダも必要になります、Content-Lengthヘッダは完全なファイルのアップロードのために必要とされます:

  • Content-Length。 チャンクサイズをセットします、あるいは最後のリクエストの場合にはそれより少なくなるかもしれません。
  • Content-Range: ファイル内のどのバイトをアップロードしているか示すためにセットします。 例えば、Content-Range: bytes 0-524287/2000000は、2,000,000バイトのファイル内の最初の 524,288バイト(256 x 1024 x 2)を提供していることを示します。

チャンクサイズの制限: アップロードを完了する最後のチャンクを除き、すべてのチャンクは、サイズが 256 KB(256 x 1024バイト)の倍数でなければなりません。 もしチャンクを使用するならば、効率的なアップロードを維持するためにできる限り大きなチャンクサイズを維持することが重要です。

例: 再開可能なチャンクされたファイルのアップロードリクエスト

最初の 524,888バイトを送信するリクエストは、このようになります:

PUT {session_uri} HTTP/1.1
Host: www.googleapis.com
Content-Length: 524288
Content-Type: image/png
Content-Range: bytes 0-524287/2000000

bytes 0-524288

もしリクエストが成功したならば、サーバは、これまでに格納された総バイト数を識別するための Rangeヘッダとともに、308 Resume Incompleteをレスポンスします。

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-524287

次のチャンクを開始する場所を決定するために、Rangeヘッダにて返された上限値を使用します。 ファイル全体がアップロードされるまで、それぞれのチャンクを PUTし続けます。

もし任意のチャンクの PUTリクエストが中断されたならば、あるいはサーバから HTTP 503 Service Unavailableあるいは他の 5xxレスポンスを受け取ったならば、中断されたアップロードを再開するにて概説された手順に従いますが、ファイルの残りをアップロードする代わりに、単にその時点からチャンクをアップロードし続けます。

重要な注意事項:

  • 次のチャンクを開始する場所を決定するために、レスポンス内の Rangeヘッダを使用してください; サーバが以前のリクエストにて送信したすべてのバイトを受信していることを想定しないでください。
  • それぞれのアップロード URIは、有限の寿命を持っており、最終的には失効します(もし使用されなければ、1日ほど以内に)。 このような理由から、アップロード URIを取得するとすぐに再開可能なアップロードを開始すること、中断が発生した直後に中断されたアップロードを再開することをお勧めします。
  • もし失効したアップロードセッション IDを用いてリクエストを送信したならば、サーバは 404 Not Foundステータスコードを返します。 この場合、新しい再開可能なアップロードを開始し、新しいアップロード URIを取得し、新しいエンドポイントを使用して最初からアップロードを開始しなければなりません。

ファイル全体のアップロードが完了したとき、サーバはこのリソースに関連付けられたメタデータとともに HTTP 201 Createdをレスポンスします。 もし、このリクエストが新しいものを作成したというよりむしろ既存のエンティティを更新したものであれば、完了したアップロードの HTTPレスポンスコードは 200 OKになるでしょう。


中断されたアップロードを再開する

もしアップロードリクエストがレスポンスを受信する前に終了したならば、あるいは、もしサーバから HTTP 503 Service Unavailableレスポンスを受信したならば、中断されたアップロードを再開する必要があります。 これを行うには:

  1. 状態をリクエストします。 アップロード URIに空の PUTリクエストを発行することによってアップロードの現在のステータスをクエリします。 このリクエストでは、HTTPヘッダは、ファイル内の現在の位置が不明であることを示す Content-Rangeヘッダを含む必要があります。 例えば、合計ファイルの長さが 2,000,000である場合、Content-Range*/2000000をセットします。 もしファイルの完全なサイズを知らなければ、Content-Range*/*をセットします。

    備考: アップロードが中断された場合だけでなく、チャンク間にステータスをリクエストすることができます。 これは、例えば、レガシーなブラウザにアップロードの進行状況を示したい場合に有用です。

  2. アップロードされたバイト数を取得します。 ステータスクエリからのレスポンスを処理します。 サーバは、これまでに受信したバイトを指定するために、そのレスポンス内に Rangeヘッダを使用します。 例えば、0-299999Rangeヘッダは、ファイルの最初の 300,000バイトが受信されたことを示しています。
  3. 残りのデータをアップロードします。 最後に、今やリクエストを再開する場所を知ったので、残りのデータあるいは現在のチャンクを送信します。 いずれの場合でも、残りのデータを分割されたチャンクとして扱う必要があるので、アップロードを再開するときに 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エラーを、最初から全体のアップロードをやり直すことによって処理します。

指数のバックオフ

指数のバックオフは、クライアントが、失敗したリクエストを時間の量を増加させながら定期的にリトライするという、ネットワークアプリケーションにとって標準的なエラー処理戦略です。 もし、多量のリクエストあるいは大量のネットワークトラフィックがサーバにエラーを返すことを引き起こすならば、指数のバックオフはこれらのエラーを処理するための良い戦略になるかもしれません。 逆に、無効な認証資格情報、あるいは、ファイルが見つからないエラーといった、ネットワーク量あるいはレスポンス時間とは無関係のエラーを扱うための適切な戦略ではありません。

適切に使用された指数のバックオフは、効率的な帯域幅の使用を増加させ、正常なレスポンスを取得するために必要とされるリクエスト数を減少させ、コンカレントな環境にてリクエストのスループットを最大化させます。

シンプルな指数のバックオフを実装するためのフローは次のとおりです:

  1. APIにリクエストします。
  2. HTTP 503レスポンスを受信します、それはリクエストをリトライする必要があることを示します。
  3. 1秒 + random_number_milliseconds 待ち、リクエストをリトライします。
  4. HTTP 503レスポンスを受信します、それはリクエストをリトライする必要があることを示します。
  5. 2秒 + random_number_milliseconds 待ち、リクエストをリトライします。
  6. HTTP 503レスポンスを受信します、それはリクエストをリトライする必要があることを示します。
  7. 4秒 + random_number_milliseconds 待ち、リクエストをリトライします。
  8. HTTP 503レスポンスを受信します、それはリクエストをリトライする必要があることを示します。
  9. 8秒 + random_number_milliseconds 待ち、リクエストをリトライします。
  10. HTTP 503レスポンスを受信します、それはリクエストをリトライする必要があることを示します。
  11. 16秒 + random_number_milliseconds 待ち、リクエストをリトライします。
  12. 停止します。 エラーを報告あるいは記録します。

上記のフローにて、random_number_millisecondsは 1000以下のランダムな数のミリ秒です。 これは必要です、なぜなら、小さなランダムの遅延を導入することは、負荷をより均等に分散し、サーバを暴走させる可能性を避けることに役立つからです。 random_number_millisecondsの値は、それぞれの待機の後に再定義されなければなりません。

備考: 待機は、常に (2 ^ n) + random_number_millisecondsです、そこでは、nは初期値が 0に定義された単調に増加する整数です。 整数 nは、それぞれの反復(それぞれのリクエスト)のために 1だけインクリメントされます。

アルゴリズムは nが 5のときに終了するようセットされています。 この上限は、クライアントが無限にリトライすることを防ぎ、リクエストが "an unrecoverable error" とみなされる前に、全体で約 32秒の遅延をもたらします。 リトライの最大数をより大きくすることは、特に長いアップロードが進行中である場合に、良いです; 例えば 1分未満というように、何か合理的にリトライの遅延をキャップしてください。