再開可能なアップロード

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

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

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

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

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

httplib2.debuglevel = 4

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

再開可能な動画アップロードを開始するには、次の URL に POST リクエストを送信します。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 サーバーは HTTP ステータス コード 200OK)のレスポンスを返します。レスポンスには、再開可能なセッションの 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 値を減算してこの値を計算できます。どちらの値も Content-Range ヘッダーで使用されます。

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

    • FIRST_BYTE – 何バイト目からアップロードを再開するかを示す数値的指標(0 から開始)。この値は、前の手順で取得した Range ヘッダーの 2 番目の数値より 1 大きい値です。上の例では、Range ヘッダーの値は 0-999999 であるため、その後の再開されたアップロードの最初のバイトは 1000000 になります。

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

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

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

    そのため、再開したアップロードでアップロードされる最初のバイトは、YouTube に正常にアップロードされた最後のバイトの次のバイトである必要があります。(ステップ 4.2Range ヘッダーの説明をご覧ください)。

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

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

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

ファイルをチャンクでアップロードする方法についての説明は、上記の 4 つのステップとほぼ同じです。ただし、ファイルのアップロードを開始するリクエスト(上記のステップ 3)とアップロードを再開するリクエスト(上記のステップ 4.3)の両方で、ファイルがチャンクでアップロードされている場合、Content-Length ヘッダー値と Content-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 ヘッダーで返された上限値を使用して、次のチャンクの開始位置を決定します。ステップ 4.3: アップロードを再開するで説明されているように、PUT リクエストを送信し続け、ファイル全体がアップロードされるまで後続のファイル チャンクをアップロードします。

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

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

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