再開可能アップロード

Google API 用の再開可能アップロード プロトコルを使用して、動画のアップロードの信頼性を向上させることができます。このプロトコルを使用すると、ネットワークの中断などの通信障害が発生しても後でアップロードの操作を再開することができるので、ネットワーク障害時の時間と帯域幅の節約につながります。

再開可能アップロードが特に有効なケースは次のとおりです。

  • 大きなファイルを転送する場合。
  • ネットワーク中断の可能性が高い場合。
  • 携帯端末などの低帯域幅な端末、またはインターネット接続が不安定な端末からアップロードする場合。

このガイドでは、再開可能アップロード プロセスを使用して動画をアップロードするためにアプリケーションが作成する一連の HTTP リクエストについて説明します。Google APIs Client Library では一部で再開可能アップロードのネイティブ サポートを提供していますが、このガイドは主にこのライブラリを利用できないデベロッパーを対象としています。一方、YouTube Data API – 動画のアップロードのガイドでは Google APIs Client Library for Python を使用して再開可能アップロード プロセスで動画をアップロードする方法を説明しています。

注: HTTP ロギングを有効化して Google API Client Library を使用することで、再開可能アップロードなどの API 操作のために作成された一連のリクエストを確認できます。たとえば、Python の HTTP トレースを有効化するには httplib2 ライブラリを使用します。

httplib2.debuglevel = 4

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

再開可能アップロードを開始するには、次の URL にリクエストを送信します。この URL の part パラメータ値にはリクエストに適した値を設定してください。このパラメータ値には設定しようとしているプロパティを含めるパートを指定します。また、API レスポンスを含めるパートも指定できます。リクエスト URL 内のパラメータ値は URL エンコードする必要があります。

https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=PARTS

video リソースに対するリクエストのボディを設定します。さらに、次の HTTP リクエスト ヘッダーも設定します。

  • Authorization – リクエストの認証トークン。
  • Content-Length – リクエストのボディで提供するバイト数。チャンク形式の転送エンコードを使用する場合は、このヘッダーを指定する必要はありません。
  • Content-Type – 値を application/json; charset=UTF-8 に設定します。
  • X-Upload-Content-Length – 後続のリクエストでアップロードされるバイト数。値として、アップロードするファイルのサイズを設定します。
  • x-upload-content-type – アップロードするファイルの MIME タイプ。ファイルは任意の動画用 MIME タイプ(video/*)または MIME タイプ application/octet-stream でアップロードできます。

以下は動画をアップロードするための再開可能セッションの開始方法を示す例です。このリクエストでは video リソースの snippet および status パートのプロパティを設定(および取得)します。また、リソースの contentDetails パートのプロパティを取得します。

post /upload/youtube/v3/videos?uploadtype=resumable&part=parts http/1.1
host: www.googleapis.com
authorization: bearer auth_token
content-length: content_length
content-type: application/json; charset=utf-8
x-upload-content-length: x_upload_content_length
X-Upload-Content-Type: X_UPLOAD_CONTENT_TYPE

video resource

以下の POST リクエストの例では、認証トークンを除いて上記のすべての値が設定されています。この例の categoryId 値は動画のカテゴリに対応します。サポートされるカテゴリのリストは、API の videoCategories.list メソッドを使用して取得できます。

POST /upload/youtube/v3/videos?uploadType=resumable&part=snippet,status,contentDetails HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer AUTH_TOKEN
Content-Length: 278
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Length: 3000000
X-Upload-Content-Type: video/*

{
  "snippet": {
    "title": "My video title",
    "description": "This is a description of my video",
    "tags": ["cool", "video", "more keywords"],
    "categoryId": 22
  },
  "status": {
    "privacyStatus": "public",
    "embeddable": True,
    "license": "youtube"
  }
}

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

リクエストが成功すると、API サーバーは 200OK)HTTP ステータス コードで応答します。このレスポンスに、再開可能セッションの URI を指定する Location HTTP ヘッダーが含まれます。これは動画ファイルのアップロードに使用する URI です。

以下は、ステップ 1 でのリクエストに対する API レスポンスの例です。

HTTP/1.1 200 OK
Location: https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&upload_id=xa298sd_f&part=snippet,status,contentDetails
Content-Length: 0

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

API レスポンスからセッション URI を抽出したら、その場所に実際の動画ファイルのコンテンツをアップロードする必要があります。リクエストのボディは、アップロードする動画のバイナリ ファイル コンテンツです。以下はリクエストの形式を示す例です。

PUT UPLOAD_URL HTTP/1.1
Authorization: Bearer AUTH_TOKEN
Content-Length: CONTENT_LENGTH
Content-Type: CONTENT_TYPE

BINARY_FILE_DATA

リクエストは、次の HTTP リクエスト ヘッダーを設定します。

  • Authorization – リクエストの認証トークン。
  • Content-Length – アップロードするファイルのサイズ。この値はステップ 1 の X-Upload-Content-Length HTTP リクエスト ヘッダーの値と同じである必要があります。
  • Content-Type – アップロードするファイルの MIME タイプ。この値はステップ 1 の X-Upload-Content-Type HTTP リクエスト ヘッダーの値と同じである必要があります。

ステップ 4 - アップロード プロセスを完了する

リクエストの結果は、次のいずれかのシナリオとなります。

  • アップロードが成功する

    API サーバーが HTTP 201Created)レスポンス コードを返します。レスポンスのボディは、作成した video リソースです。

  • アップロードは失敗したが、再開可能

    次のいずれかのケースでは、アップロードは再開可能です。

    • アプリケーションと API サーバーの間の接続が失われたためにリクエストが中断した場合。このケースでは API レスポンスを受け取りません。

    • API レスポンスに、次のいずれかの 5xx レスポンス コードが含まれている場合。これらのレスポンス コードを受け取った後でアップロードを再開するには、指数バックオフという方法を使用する必要があります。

      • 500Internal Server Error
      • 502Bad Gateway
      • 503Service Unavailable
      • 504Gateway Timeout

    アップロードを再開するには、下記のアップロード ステータスを確認するアップロードを再開するの説明に従ってください。再開可能セッション URI の存続期間は有限で、最終的には期限切れとなります。このため、セッション URI を取得したら即座に再開可能アップロードを開始し、中断が発生したら速やかにアップロードを再開することをおすすめします。

  • アップロードが完全に失敗する

    アップロードが失敗すると、レスポンスには失敗の原因を説明するエラー レスポンスが含まれます。完全に失敗したアップロードの場合、API レスポンスには 4xx レスポンス コードか、上記以外の 5xx レスポンス コードが含まれます。

    期限切れのセッション URI を送信した場合、サーバーは 404 HTTP レスポンス コード(Not Found)を返します。このようなケースでは新しい再開可能アップロードを開始し、新しいセッション URI を取得して、新しい URI で最初からアップロードを開始する必要があります。

ステップ 4.1: アップロード ステータスを確認する

中断した再開可能アップロードのステータスを確認するには、ステップ 2 で取得してステップ 3 で使用したアップロード URL に空の PUT リクエストを送信します。リクエストの Content-Range ヘッダー値は bytes */CONTENT_LENGTH に設定します。ここで、CONTENT_LENGTH はアップロードしているファイルのサイズです。

PUT UPLOAD_URL HTTP/1.1
Authorization: Bearer AUTH_TOKEN
Content-Length: 0
Content-Range: bytes */CONTENT_LENGTH

ステップ 4.2: API レスポンスを処理する

アップロードが既に完了している場合、成功したか失敗したかにかかわらず、API はアップロードが最初に完了したときに送信したものと同じレスポンスを返します。

ただし、アップロードが中断したか進行中の場合、API レスポンスには HTTP 308Resume Incomplete)レスポンス コードが含まれます。レスポンスの Range ヘッダーには、既にアップロードに成功したファイルの部分のバイト数が示されます。

  • このヘッダー値は 0 から始まります。したがって、ヘッダー値 0-999999 はファイルの最初の 1,000,000 バイトがアップロード済みであることを示します。
  • まだ何もアップロードされていない場合は、API レスポンスに Range ヘッダーは含まれません。

以下は、再開可能アップロードでの API レスポンスの形式を示すサンプル レスポンスです。

308 Resume Incomplete
Content-Length: 0
Range: bytes=0-999999

API レスポンスに Retry-After ヘッダーも含まれる場合は、このヘッダー値からアップロード再開を試行するタイミングを判断することができます。

ステップ 4.3: アップロードを再開する

アップロードを再開するには、ステップ 2 で取得されたアップロード URL にもう一度 PUT リクエストを送ります。リクエスト ボディには、動画ファイル中のアップロード未完了部分のバイナリ コードを設定します。

PUT UPLOAD_URL HTTP/1.1
Authorization: Bearer AUTH_TOKEN
Content-Length: REMAINING_CONTENT_LENGTH
Content-Range: bytes FIRST_BYTE-LAST_BYTE/TOTAL_CONTENT_LENGTH

PARTIAL_BINARY_FILE_DATA

設定する必要がある HTTP リクエスト ヘッダーは次のとおりです。

  • Authorization – リクエストの認証トークン。

  • Content-Length – アップロードが完了していないコンテンツのサイズ(バイト数)。ファイルの残りをアップロードする場合、TOTAL_CONTENT_LENGTH 値から FIRST_BYTE 値を差し引くことでこの値を計算できます。この 2 つの値は Content-Range ヘッダーで使用されます。

  • Content-Range – アップロードするファイルの部分。このヘッダー値は 3 つの値で構成されます。

    • FIRST_BYTE – 何バイト目からアップロードを再開するかを示す数値的指標(0 から開始)。この値は前のステップで取得された Range ヘッダーの 2 番目の数値よりも 1 大きい数値です。前述の例では Range ヘッダー値が 0-999999 だったので、後続の再開アップロードでの FIRST_BYTE は 1000000 となります。

    • LAST_BYTE – アップロードするバイナリ ファイルが何バイト目で終わるかを示す数値的指標(0 から開始)。通常、これはファイル内の最後のバイトです。したがって、ファイル サイズが 3000000 バイトであった場合、このファイルの LAST_BYTE の数値は 2999999 となります。

    • TOTAL_CONTENT_LENGTH – 動画ファイルの合計サイズ(バイト単位)。この値は最初のアップロード リクエストで指定された Content-Length ヘッダーと同じである必要があります。

    注: 不連続なバイナリ ファイル ブロックをアップロードすることはできません。不連続なブロックをアップロードしようとすると、残りのバイナリ コンテンツは一切アップロードされません。

    このように、アップロード再開での FIRST_BYTE は、YouTube へのアップロードが既に成功している LAST_BYTE の次の数値でなければなりません(ステップ 4.2Range ヘッダーについての説明を参照してください)。

    したがって、Range ヘッダーの最後の数値が 999999 である場合、アップロード再開のリクエストでの FIRST_BYTE は 1000000 とする必要があります(いずれの数値も 0 からカウントされます)。このとき 999999 以下のバイト(バイトが重複している)または 1000001 以上のバイト(バイトがスキップされている)からアップロードを再開しようとすると、バイナリ コンテツはまったくアップロードされません。

ファイルをチャンクで送信する

ファイル全体をアップロードしてネットワークが中断した場合にアップロードを再開するのではなく、アプリケーションでファイルをチャンクに分割し、一連のリクエストを送信してチャンクを順番にアップロードすることもできます。この方法が必要になることはほとんどありません。また、多くのリクエストが必要でパフォーマンスに影響を与えるため、実際にはおすすめできません。ただし、非常に不安定なネットワーク上で進捗状況を示す指標を見ようとしている場合には役立ちます。

ファイルをチャンクでアップロードする方法についての説明は、上記の 4 つのステップとほぼ同じです。ただし、ファイルをチャンクでアップロードする場合、ファイルのアップロード開始のリクエスト(上記のステップ 3)とアップロード再開のリクエスト(ステップ 4.3)で Content-LengthContent-Range のヘッダー値を別の設定にする必要があります。

  • Content-Length ヘッダー値では、該当のリクエストが送信するチャンクのサイズを指定します。チャンク サイズに関する次の制限に注意してください。

    • チャンク サイズは 256 KB の倍数である必要があります(ファイル全体のサイズは 256 KB の倍数ではない可能性もあるので、この制限は最後のチャンクには適用されません)。チャンクのサイズは大きいほど効率的です。

    • アップロード シーケンスのすべてのリクエストのチャンク サイズは等しくなければなりません。ただし、最後のチャンクのサイズを指定する最後のリクエストについては例外です。

  • Content-Range ヘッダーでは、該当のリクエストがアップロードするファイル内のバイト値を指定します。ステップ 4.3 での Content-Range ヘッダーの設定についての説明は、この値を設定するときにも当てはまります。

    たとえば、bytes 0-524287/2000000 の値はこのリクエストが 2,000,000 バイトのファイル中の最初の 524,288 バイト(256 x 2048)を送信するという意味です。

下記は、2,000,000 バイトのファイルをチャンクでアップロードする一連のリクエストの中の最初のリクエストの形式を示す例です。

PUT UPLOAD_URL HTTP/1.1
Authorization: Bearer AUTH_TOKEN
Content-Length: 524888
Content-Type: video/*
Content-Range: bytes 0-524287/2000000

{bytes 0-524287}

最後のリクエスト以外のリクエストが成功すると、API サーバーは 308Resume Incomplete)レスポンスを返します。レスポンスの形式は上記のステップ 4.2: API レスポンスを処理すると同じです。

次のチャンクをどこから開始するかを決めるには、API レスポンスの Range ヘッダーの大きい方の値を使用します。PUT リクエストの送信を続行し、ステップ 4.3: アップロードを再開するで説明したように、ファイル全体がアップロードされるまで後続のファイル チャンクをアップロードします。

ファイル全体がアップロードされると、サーバーは 201 HTTP レスポンス コード(Created)を応答し、新しく作成された動画リソースの中のリクエストされた部分を返します。

いずれかのリクエストが中断された場合、またはアプリケーションが 5xx のいずれかのレスポンス コードを受け取った場合は、ステップ 4 で説明した手順に従ってアップロードを完了させます。ただし、残りのファイルをアップロードするのではなく、アップロードを再開するポイントからチャンクのアップロードを続けます。ファイル アップロードをどこから再開するかを判別するには、必ずアップロード ステータスを確認してください。前のリクエストで送信されたバイトがすべてサーバーに受信された(あるいはまったく受信されていない)と仮定することはできません。

注: アップロードされたチャンクの間にアクティブ アップロードのステータスをリクエストすることもできます(ステータスを取得する前にアップロードを中断する必要はありません)。