メディアのアップロード

メディア アップロード機能を使用すれば、DCM/DFA Reporting and Trafficking API でクラウドにデータを保存して、サーバーで利用することができます。ここでは、写真、動画、PDF ファイル、zip ファイルといった形式のデータをアップロードできます。

この記事では、架空の Farm API でのメディア アップロードの例を示しますが、DCM/DFA Reporting and Trafficking API でも同様の方法でアップロード可能です。

アップロード オプション

DCM/DFA Reporting and Trafficking API を使えば、特定の形式のバイナリデータ、すなわちメディアをアップロードできます。アップロードできるデータの具体的な特性については、メディア アップロードをサポートするメソッドのリファレンス ページをご確認ください。

  • アップロード ファイル サイズの上限: このメソッドで保存できるデータ容量の上限です。
  • 使用できるメディア MIME タイプ: このメソッドで保存できるバイナリデータの形式です。

アップロード リクエストは次のいずれかの方法で行えます。使用するメソッドは、uploadType リクエスト パラメータで指定します。

  • シンプル アップロードuploadType=media)。小さいファイル(例: 5 MB 以下)を高速で転送します。
  • マルチパート アップロードuploadType=multipart)。小さいファイルとメタデータを高速で転送します。ファイルとそのファイルを記述するメタデータを、すべて 1 つのリクエストにまとめて転送します。
  • 再開可能アップロードuploadType=resumable)。大きいファイルで特に重要な、信頼性の高い転送を実現します。このメソッドではセッション開始リクエストを使用し、必要に応じてメタデータを追加できます。これは、ほとんどのアプリケーションに使用できるおすすめの方法です。アップロード 1 回につき HTTP リクエストを 1 つ追加するだけで、小さいファイルにも使用できます。

メディアをアップロードする際は、特別な URI を使用します。メディア アップロードをサポートするメソッドには 2 つの URI エンドポイントがあります。

  • メディア用の /upload URI。 アップロード エンドポイントの形式は、標準的なリソース URI に接頭辞「/upload」を付けたものです。この URI は、メディアデータそのものを転送する場合に使用します。例: POST /upload/farm/v1/animals
  • メタデータ用の標準的なリソース URI。リソースにデータ フィールドが含まれている場合は、これらのフィールドを使って、アップロードするファイルを記述するメタデータを格納します。メタデータの値を作成、更新する場合にこの URI を使用できます。例: POST /farm/v1/animals

シンプル アップロード

最も簡単なファイル アップロード方法は、シンプル アップロード リクエストを作成することです。この方法は次の場合におすすめします。

  • ファイルが小さく、接続に失敗した場合にファイル全体を再度アップロードできる場合。
  • メタデータを送信しない場合。たとえば、このリソースのメタデータを別のリクエストで送信する予定の場合や、メタデータがサポートされていなかったり利用できなかったりする場合が該当します。

シンプル アップロードを使用するには、メソッドの /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=media を追加します。例:

POST https://www.googleapis.com/upload/farm/v1/animals?uploadType=media

シンプル アップロード リクエストの作成時に使用する HTTP ヘッダーの内容は次のとおりです。

  • Content-Type: メソッドで使用できるアップロード メディア データタイプのいずれかに設定します(API リファレンスをご覧ください)。
  • Content-Length: アップロードするバイト数に設定します。チャンク形式の転送エンコードを使用する場合は不要です。

例: シンプル アップロード

下記は、架空の Farm API でのシンプル アップロードの使用例です。

POST /upload/farm/v1/animals?uploadType=media HTTP/1.1
Host: www.googleapis.com
Content-Type: image/jpeg
Content-Length: number_of_bytes_in_file
Authorization: Bearer your_auth_token

JPEG data

リクエストが成功すると、HTTP 200 OK ステータス コードとメタデータがサーバーから返されます。

HTTP/1.1 200
Content-Type: application/json

{
  "name": "Llama"
}

マルチパート アップロード

アップロードするデータとともにメタデータを送信する場合は、1 つの multipart/related リクエストを作成できます。これは、送信するデータが小さく、接続が失敗しても全体を再アップロードできる場合に適しています。

マルチパート アップロードを使用するには、メソッドの /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=multipart を追加します。下記はその例です。

POST https://www.googleapis.com/upload/farm/v1/animals?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 リファレンスをご覧ください。

注: 関連付けられたデータをアップロードせずに、メタデータ部分のみを生成または更新するには、単に POST または PUT リクエストを標準リソース エンドポイント(https://www.googleapis.com/farm/v1/animals)に送信します。

例: マルチパート アップロード

下記は、架空の Farm API でのマルチパート アップロード リクエストの使用例です。

POST /upload/farm/v1/animals?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

{
  "name": "Llama"
}

--foo_bar_baz
Content-Type: image/jpeg

JPEG data
--foo_bar_baz--

リクエストが成功すると、HTTP 200 OK ステータス コードとメタデータがサーバーから返されます。

HTTP/1.1 200
Content-Type: application/json

{
  "name": "Llama"
}

再開可能アップロード

データファイルのアップロードの信頼性を向上させるには、再開可能アップロード プロトコルを使用します。このプロトコルでは、通信障害でデータの送信が中断されても、後でアップロード操作を再開できます。この方法は特に、大容量のファイルを転送するときや、モバイル クライアント アプリからのアップロードなどでネットワークの中断やその他の送信エラーが起こる可能性が高いときに役立ちます。また、ネットワーク障害が発生した場合に大容量のファイルのアップロードを最初からやり直す必要がなくなり、使用する帯域幅を削減できます。

再開可能アップロードを使用する手順は次のとおりです。

  1. 再開可能セッションを開始する: メタデータ(ある場合)を含むアップロード URI への最初のリクエストを作成します。
  2. 再開可能セッション URI を保存する: 最初のリクエストのレスポンスで返された URI を保存し、後続のリクエストに使用します。
  3. ファイルをアップロードする: 再開可能セッション URI にメディア ファイルを送信します。

また、再開可能アップロードを使用するアプリには、中断されたアップロードを再開するためのコードも必要です。アップロードが中断された場合は、正常に受信されたデータの容量を確認し、その中断ポイントからアップロードを再開します。

注: アップロード URI は 1 週間後に有効期限切れとなります。

ステップ 1: 再開可能セッションを開始する

再開可能アップロードを開始するには、メソッドの /upload URI への POST リクエストまたは PUT リクエストを作成し、クエリ パラメータ uploadType=resumable を追加します。下記はその例です。

POST https://www.googleapis.com/upload/farm/v1/animals?uploadType=resumable

この最初のリクエストでは、本体は空またはメタデータのみのいずれかです。アップロードするファイルの実際の内容は後続のリクエストで転送します。

最初のリクエストでは次の HTTP ヘッダーを使用します。

  • X-Upload-Content-Type: 後続のリクエストで転送するアップロード データのメディア MIME タイプに設定します。
  • X-Upload-Content-Length: 後続のリクエストで転送するアップロード データのバイト数に設定します。このリクエストの時点でデータの長さが不明な場合は省略できます。
  • Content-Type(メタデータを提供する場合):メタデータのデータ型に合わせて設定します。
  • Content-Length: 最初のリクエストの本体で提供するバイト数に設定します。チャンク形式の転送エンコードを使用する場合は不要です。

各メソッドで使用できるメディア MIME タイプの一覧とアップロード ファイルのサイズの上限については、API リファレンスをご覧ください。

例: 再開可能セッションの最初のリクエスト

次に、架空の Farm API における再開可能セッションの開始方法の例を示します。

POST /upload/farm/v1/animals?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/jpeg
X-Upload-Content-Length: 2000000

{
  "name": "Llama"
}

注: 最初の再開可能な更新リクエストをメタデータなしで発行する場合は、リクエスト本文を空のままにして、Content-Length ヘッダーを 0 に設定します。

次に、レスポンスの処理方法について説明します。

ステップ 2: 再開可能セッション URI を保存する

セッション開始リクエストが成功すると、API サーバーは HTTP ステータス コード 200 OK のレスポンスを返します。また、再開可能なセッション URI を指定した Location ヘッダーも返します。下の例に示されている Location ヘッダーには、このセッションで使用する一意のアップロード ID を指定した upload_id クエリ パラメータ部分が含まれています。

例: 再開可能セッションの最初のレスポンス

ステップ 1 のリクエストに対するレスポンスは次のとおりです。

HTTP/1.1 200 OK
Location: https://www.googleapis.com/upload/farm/v1/animals?uploadType=resumable&upload_id=xa298sd_sdlkj2
Content-Length: 0

上のレスポンス例に示されている Location ヘッダーの値は、実際にファイルをアップロードするとき、またはアップロード ステータスを照会するときに HTTP エンドポイントとして使用するセッション URI です。

後続のリクエストで使用できるように、セッション URI をコピーして保存します。

ステップ 3: ファイルをアップロードする

ファイルをアップロードするには、前述のステップで取得したアップロード URI に PUT リクエストを送信します。アップロード リクエストの形式は次のとおりです。

PUT session_uri

再開可能なファイル アップロードのリクエストを作成するときに使用する HTTP ヘッダーには、Content-Length を含めます。この値は、このリクエストでアップロードするバイト数(通常はアップロード ファイルのサイズ)に設定します。

例: 再開可能ファイルのアップロード リクエスト

この例で 2,000,000 バイトの JPEG ファイル全体をアップロードするための再開可能リクエストは次のようになります。

PUT https://www.googleapis.com/upload/farm/v1/animals?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1
Content-Length: 2000000
Content-Type: image/jpeg

bytes 0-1999999

リクエストが成功すると、サーバーは HTTP 201 Created のレスポンスを、このリソースに関連付けられているメタデータとともに返します。再開可能なセッションの最初のリクエストが PUT だった場合、既存のリソースを更新したときの成功のレスポンスは 200 OK となり、このリソースに関連付けられているメタデータが返されます。

アップロード リクエストが中断された場合や、サーバーから HTTP 503 Service Unavailable などの 5xx レスポンスが返された場合は、中断されたアップロードを再開するに記載された手順に従ってください。


チャンクでファイルをアップロードする

再開可能アップロードでは、ファイルをチャンクに分割し、一連のリクエストを送信して各チャンクを順番にアップロードすることもできますが、そのリクエストの分だけパフォーマンス コストがかかるため、おすすめしません。また、通常はこの方法が必要になることはありません。ただし、1 つのリクエストで転送するデータの量を減らすために、チャンクの使用が必要になることもあります。Google App Engine リクエストの一部のクラスのように、リクエストごとに固定の時間制限がある場合は、この方法が役立ちます。また、デフォルトでアップロードの進捗状況がサポートされていない従来のブラウザで、アップロード進捗状況を提供することも可能です。


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

レスポンスを受信する前にアップロード リクエストが終了した場合や、サーバーから HTTP 503 Service Unavailable レスポンスが返された場合は、中断されたアップロードを再開する必要があります。その方法は次のとおりです。

  1. ステータスをリクエストする: 空の PUT リクエストをアップロード URI に発行して、アップロードの現在のステータスを照会します。このリクエストの HTTP ヘッダーには、ファイルの現在の位置が不明であることを示す Content-Range ヘッダーを含める必要があります。たとえば、ファイルの合計サイズが 2,000,000 の場合、Content-Range*/2000000 に設定します。ファイル全体のサイズがわからない場合は、Content-Range*/* に設定します。

    注: アップロードが中断された場合だけでなく、チャンクとチャンクの間にもステータスをリクエストできます。たとえば、従来のブラウザでアップロードの進捗状況を表示したい場合に役立ちます。

  2. アップロードされたバイト数を取得する: ステータス クエリからのレスポンスを処理します。サーバーはレスポンスの Range ヘッダーを使用して、その時点までに何バイト受信したかを示します。たとえば、Range ヘッダーが 0-299999 の場合、ファイルの先頭から 300,000 バイトを受信したという意味になります。
  3. 残りのデータをアップロードする: 最後に、リクエストの再開ポイントが判明したら、残りのデータまたは現在のチャンクを送信します。どちらの場合も、残りのデータを独立したチャンクとして扱う必要があります。つまり、アップロードを再開するときに Content-Range ヘッダーを送信する必要があります。
例: 中断されたアップロードを再開する

1)アップロード ステータスをリクエストする。

次のリクエストでは、Content-Range ヘッダーを使用して、2,000,000 バイトのファイルで現在の位置が不明であることを示しています。

PUT {session_uri} HTTP/1.1
Content-Length: 0
Content-Range: bytes */2000000

2)レスポンスから、これまでにアップロードされたバイト数を抽出する。

サーバーのレスポンスの Range ヘッダーは、これまでにファイルの先頭の 43 バイトを受信したことを示しています。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 または 410 Gone エラーが発生した場合には、最初から全体のアップロードをやり直します。

指数バックオフ

指数バックオフは、失敗したリクエストをクライアントが再試行する際、失敗するごとに次の再試行までの待ち時間を増やしていく、ネットワーク アプリケーションに使われる標準的なエラー処理方法です。リクエスト数やネットワーク トラフィックが多いためにサーバーがエラーを返す場合は、指数バックオフでこうしたエラーを処理することをおすすめします。逆に、認証情報が無効な場合やファイルが見つからない場合など、ネットワーク量や応答時間とは無関係なエラーの処理には適しません。

指数バックオフを正しく使用すれば、帯域利用の効率を高め、レスポンスを正しく取得するために必要なリクエストの数を減らし、同時実行環境におけるリクエストのスループットを最大化することができます。

単純な指数バックオフを実装するフローは次のとおりです。

  1. API にリクエストを送ります。
  2. リクエストの再試行が必要であることを示す HTTP 503 レスポンスを受信します。
  3. random_number_milliseconds に 1 秒追加した時間を待機してから、リクエストを再試行します。
  4. リクエストの再試行が必要であることを示す HTTP 503 レスポンスを受信します。
  5. random_number_milliseconds に 2 秒追加した時間を待機してから、リクエストを再試行します。
  6. リクエストの再試行が必要であることを示す HTTP 503 レスポンスを受信します。
  7. random_number_milliseconds に 4 秒追加した時間を待機してから、リクエストを再試行します。
  8. リクエストの再試行が必要であることを示す HTTP 503 レスポンスを受信します。
  9. random_number_milliseconds に 8 秒追加した時間を待機してから、リクエストを再試行します。
  10. リクエストの再試行が必要であることを示す HTTP 503 レスポンスを受信します。
  11. random_number_milliseconds に 16 秒追加した時間を待機してから、リクエストを再試行します。
  12. 停止します。エラーが報告または記録されます。

上記フローで、random_number_milliseconds は 1,000 ミリ秒以下のランダムなミリ秒です。これは、短いランダムな遅延を挿入することで負荷をより均等に分散させ、サーバーの過負荷が発生するのを防ぐために必要です。random_number_milliseconds の値は各待機の後に再定義する必要があります。

注: 待機時間は常に (2 ^ n) + random_number_milliseconds となります。この n は最初にゼロとして定義され、後は単調に増加する整数です。整数 n は、反復(リクエスト)のたびに 1 つずつ増加します。

このアルゴリズムは、n が 5 になると終了するように設定されています。この上限によって、クライアントが無限に再試行を繰り返すことを防ぎます。総遅延時間が約 32 秒になると、リクエストは「回復不能なエラー」と判断されます。再試行の最大回数を増やすこともできます(特に、長いアップロードを行う場合)。ただし、再試行の遅延時間には合理的な上限を設定してください(たとえば 1 分未満)。