Przesyłanie z możliwością wznowienia

Możesz przesyłać filmy w bardziej niezawodny sposób, korzystając z protokołu umożliwiającego wznowienie przesyłania w interfejsach Google API. Ten protokół umożliwia wznowienie operacji przesyłania po przerwie w działaniu sieci lub innym błędzie transmisji, co pozwala zaoszczędzić czas i przepustowość w przypadku awarii sieci.

Przerywane przesyłanie jest szczególnie przydatne w tych sytuacjach:

  • Przenosisz duże pliki.
  • Prawdopodobieństwo przerwania połączenia jest wysokie.
  • Przesyłanie danych pochodzi z urządzenia o niskiej przepustowości lub niestabilnym połączeniu z internetem, takiego jak urządzenie mobilne.

W tym przewodniku opisujemy sekwencję żądań HTTP, które aplikacja wysyła, aby przesłać filmy za pomocą procesu przerywanego przesyłania. Ten przewodnik jest przeznaczony przede wszystkim dla deweloperów, którzy nie mogą korzystać z bibliotek klienta interfejsu API Google, z których niektóre obsługują wbudowane wznawialne przesyłanie. W przewodniku YouTube Data API – przesyłanie filmu znajdziesz informacje o tym, jak za pomocą biblioteki klienta interfejsów API Google dla języka Python przesłać film przy użyciu procesu umożliwiającego wznowienie przesyłania.

Uwaga: możesz też wyświetlić serię żądań wysłanych w ramach przerywanego przesyłania lub innej operacji interfejsu API, korzystając z jednej z bibliotek klienta interfejsu API Google z włączonym rejestrowaniem HTTPS. Aby na przykład włączyć śledzenie HTTP w Pythonie, użyj biblioteki httplib2:

httplib2.debuglevel = 4

Krok 1. Rozpocznij sesję z możliwością wznowienia

Aby rozpocząć przerywane przesyłanie filmu, wyślij żądanie POST na ten adres URL. W adresie URL ustaw wartość parametru part na odpowiednią dla Twojego żądania. Pamiętaj, że wartość parametru identyfikuje części zawierające właściwości, które ustawiasz, a także części, które mają być uwzględnione w odpowiedzi interfejsu API. Wartości parametrów w adresie URL żądania muszą być zakodowane na potrzeby adresu URL.

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

W treści żądania ustaw zasób video. Ustaw też te nagłówki żądania HTTP:

  • Authorization – token autoryzacji żądania.
  • Content-Length – liczba bajtów podana w treści żądania. Jeśli używasz kodowania transferu w porcjach, nie musisz podawać tego nagłówka.
  • Content-Type – ustaw wartość na application/json; charset=UTF-8.
  • X-Upload-Content-Length – liczba bajtów, które zostaną przesłane w kolejnych żądaniach. Ustaw tę wartość na rozmiar pliku, który przesyłasz.
  • x-upload-content-type – typ MIME pliku, który przesyłasz. Możesz przesyłać pliki z dowolnym typem MIME wideo (video/*) lub typem MIME application/octet-stream.

Poniższy przykład pokazuje, jak zainicjować sesję z możliwością wznowienia w celu przesłania filmu. Żądanie ustawia (i pobiera) właściwości w częściach snippet i status zasobu video, a także pobiera właściwości w części contentdetails zasobu.

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

Ten przykład pokazuje żądanie POST z wszystkimi wypełnionymi wartościami z wyjątkiem tokena uwierzytelniania. Wartość categoryId w tym przykładzie odpowiada kategorii filmu. Listę obsługiwanych kategorii można pobrać za pomocą metody videoCategories.list interfejsu API.

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"
  }
}

Krok 2. Zapisz identyfikator URI sesji, którą można wznowić

Jeśli żądanie zakończy się powodzeniem, serwer interfejsu API odpowie kodem stanu HTTP 200 (OK), a w odpowiedzi znajdzie się nagłówek HTTP Location, który określa adres URI sesji z możliwością wznowienia. To jest adres URI, którego użyjesz do przesłania pliku wideo.

Przykład poniżej pokazuje przykładową odpowiedź interfejsu API na żądanie z kroku 1:

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

Krok 3. Prześlij plik wideo

Po wyodrębnieniu identyfikatora URI sesji z odpowiedzi interfejsu API musisz przesłać do tej lokalizacji rzeczywistą zawartość pliku wideo. Treść żądania to zawartość pliku binarnego filmu, który przesyłasz. Przykład poniżej pokazuje format żądania.

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

BINARY_FILE_DATA

Żądanie to ustawia te nagłówki żądania HTTP:

  • Authorization – token autoryzacji żądania.
  • Content-Length – rozmiar przesyłanego pliku. Ta wartość powinna być taka sama jak wartość nagłówka żądania HTTP X-Upload-Content-Length w kroku 1.
  • Content-Type – typ MIME pliku, który przesyłasz. Ta wartość powinna być taka sama jak wartość nagłówka żądania HTTP X-Upload-Content-Type w kroku 1.

Krok 4. Dokończ proces przesyłania

Twoja prośba spowoduje jeden z tych scenariuszy:

  • Przesłanie zostało zakończone.

    Serwer interfejsu API odpowiada kodem odpowiedzi HTTP 201 (Created). Treść odpowiedzi to utworzony przez Ciebie zasób video.

  • Przesłanie nie powiodło się, ale można je wznowić.

    Przesyłanie możesz wznowić w jednym z tych przypadków:

    • Twoje żądanie zostało przerwane, ponieważ połączenie między aplikacją a serwerem interfejsu API zostało utracone. W takim przypadku nie otrzymasz odpowiedzi API.

    • Odpowiedź interfejsu API zawiera jeden z tych kodów odpowiedzi: 5xx. Gdy po otrzymaniu któregokolwiek z tych kodów odpowiedzi wznowisz przesyłanie, Twój kod powinien używać strategii wzrastającego czasu do ponowienia.

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

    Aby wznowić przesyłanie, wykonaj instrukcje sprawdzania stanu przesyłaniawznawiania przesyłania. Pamiętaj, że każdy adres URI sesji z możliwością wznowienia ma ograniczony czas trwania i ostatecznie wygasa. Dlatego zalecamy rozpoczęcie przerywanego przesyłania zaraz po uzyskaniu identyfikatora URI sesji i wznowienie przerwanego przesyłania zaraz po przerwaniu.

  • Przesłanie nie powiodło się na stałe.

    W przypadku nieudanego przesyłania odpowiedź zawiera odpowiedź na błąd, która wyjaśnia przyczynę niepowodzenia. W przypadku trwałego niepowodzenia przesyłania odpowiedź interfejsu API będzie zawierać kod odpowiedzi 4xx lub 5xx inny niż wymienione powyżej.

    Jeśli wyślesz żądanie z identyfikatorem URI sesji, której ważność wygasła, serwer zwróci kod odpowiedzi HTTP 404 (Not Found). W tym przypadku musisz rozpocząć nowe przesyłanie z możliwością wznowienia, uzyskać nowy identyfikator URI sesji i rozpocząć przesyłanie od początku, używając nowego identyfikatora URI.

Krok 4.1. Sprawdź stan przesyłania

Aby sprawdzić stan przerwanego przesyłania, które można wznowić, wyślij puste żądanie PUT do adresu URL przesyłania, który został pobrany w kroku 2 i użyty w kroku 3. W żądaniu ustaw wartość nagłówka Content-Range na bytes */CONTENT_LENGTH, gdzie CONTENT_LENGTH to rozmiar przesyłanego pliku.

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

Krok 4.2. Przetwarzanie odpowiedzi interfejsu API

Jeśli przesyłanie zostało już zakończone, niezależnie od tego, czy było udane, interfejs API zwróci tę samą odpowiedź, którą wysłał podczas pierwotnego przesyłania.

Jeśli jednak przesyłanie zostało przerwane lub jest nadal w toku, odpowiedź interfejsu API będzie miała kod odpowiedzi HTTP 308 (Resume Incomplete). W odpowiedzi nagłówek Range określa, ile bajtów pliku zostało już przesłanych.

  • Wartość nagłówka jest indeksowana od 0. Wartość nagłówka 0-999999 wskazuje, że przesłano pierwsze 1,000,000 bajtów pliku.
  • Jeśli nic nie zostało jeszcze przesłane, odpowiedź interfejsu API nie będzie zawierać nagłówka Range.

Przykładowa odpowiedź poniżej pokazuje format odpowiedzi interfejsu API dla przerywanego przesyłania:

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

Jeśli odpowiedź interfejsu API zawiera też nagłówek Retry-After, użyj jego wartości, aby określić, kiedy spróbować wznowić przesyłanie.

Krok 4.3. Wznów przesyłanie

Aby wznowić przesyłanie, wyślij kolejne żądanie PUT na adres URL przesyłania danych zarejestrowany w kroku 2. Ustaw treść żądania na kod binarny dla części pliku wideo, która nie została jeszcze przesłana.

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

Musisz ustawić te nagłówki żądania HTTP:

  • Authorization – token autoryzacji żądania.

  • Content-Length – rozmiar (w bajtach) treści, które nie zostały jeszcze przesłane. Jeśli przesyłasz pozostałą część pliku, możesz obliczyć tę wartość, odejmując wartość FIRST_BYTE od wartości TOTAL_CONTENT_LENGTH. Obie wartości są używane w nagłówku Content-Range.

  • Content-Range – część pliku, który przesyłasz. Wartość nagłówka składa się z 3 wartości:

    • FIRST_BYTE – liczony od 0 indeks bajtu, od którego wznawiasz przesyłanie. Ta wartość jest o jedną większą od drugiej liczby w nagłówku Range pobranym w poprzednim kroku. W poprzednim przykładzie wartość nagłówka Range wynosiła 0-999999, więc pierwszy bajt w kolejne wznowione przesyłanie będzie miał wartość 1000000.

    • LAST_BYTE – liczony od 0 numeryczny indeks ostatniego bajtu przesyłanego pliku binarnego. Zwykle jest to ostatni bajt w pliku. Jeśli na przykład rozmiar pliku to 3000000 bajtów, ostatni bajt w pliku będzie miał numer 2999999.

    • TOTAL_CONTENT_LENGTH – łączny rozmiar pliku wideo w bajtach. Ta wartość jest taka sama jak nagłówek Content-Length podany w pierwotnym żądaniu przesłania.

    Uwaga: nie możesz przesłać nieciągłego bloku pliku binarnego. Jeśli spróbujesz przesłać blok nieciągły, nie zostanie przesłana żadna pozostała zawartość binarna.

    W związku z tym pierwszy bajt przesłany podczas wznawianego przesyłania musi być następnym bajtem po ostatnim bajcie, który został już przesłany do YouTube. (patrz omówienie nagłówka Rangekroku 4.2).

    Jeśli więc ostatni bajt w nagłówku Range to 999999, pierwszy bajt w żądaniu wznowienia przesyłania musi być równy 1000000. (oba numery używają indeksu o wartości 0). Jeśli spróbujesz wznowić przesyłanie od bajtu 999999 lub niższego (nakładające się bajty) albo od bajtu 1000001 lub wyższego (przeskakiwanie bajtów), żadna część danych binarnych nie zostanie przesłana.

Przesyłanie pliku w częściach

Zamiast próby przesłania całego pliku i wznowienia przesyłania w przypadku przerwy w działaniu sieci aplikacja może podzielić plik na części i wysłać serię próśb o przesłanie tych części kolejno. Takie podejście jest rzadko konieczne i nie zalecamy go, ponieważ wymaga dodatkowych żądań, które mają wpływ na wydajność. Może to być jednak przydatne, jeśli chcesz wyświetlić wskaźnik postępu w bardzo niestabilnej sieci.

Instrukcje przesyłania pliku w kawałkach są prawie identyczne z 4-etapowym procesem opisanym wcześniej w tym przewodniku. Jednak żądania rozpoczęcia przesyłania pliku (krok 3 powyżej) i wznowienia przesyłania (krok 4.3 powyżej) ustawiają wartości nagłówków Content-Length i Content-Range inaczej, gdy plik jest przesyłany w kawałkach.

  • Wartość nagłówka Content-Length określa rozmiar fragmentu, który jest wysyłany w ramach żądania. Pamiętaj o tych ograniczeniach dotyczących rozmiarów fragmentów:

    • Rozmiar fragmentu musi być wielokrotnością 256 KB. (To ograniczenie nie dotyczy ostatniego fragmentu, ponieważ rozmiar całego pliku może nie być wielokrotnością 256 KB). Pamiętaj, że większe fragmenty są bardziej wydajne.

    • Rozmiar części musi być taki sam w przypadku każdego żądania w sekwencji przesyłania, z wyjątkiem ostatniego żądania, które określa rozmiar ostatniej części.

  • Nagłówek Content-Range określa bajty w pliku, który żądanie przesyła. Podczas ustawiania tej wartości obowiązują instrukcje dotyczące ustawiania nagłówka Content-Range podane w kroku 4.3.

    Wartość bytes 0-524287/2000000 oznacza na przykład, że żądanie wysyła pierwsze 524 288 bajtów (256 x 2048) z pliku o rozmiarze 2 000 000 bajtów.

Przykład poniżej pokazuje format pierwszego z serii żądań, które prześlą plik o długości 2 000 000 bajtów w porcjach:

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}

Jeśli żądanie inne niż ostatnie zostanie zrealizowane, serwer interfejsu API odpowie kodem 308 (Resume Incomplete). Format odpowiedzi będzie taki sam jak w kroku 4.2: Przetwarzanie odpowiedzi interfejsu API.

Aby określić, gdzie ma się zacząć kolejny fragment, użyj górnej wartości zwróconej w nagłówku Range odpowiedzi interfejsu API. Kontynuuj wysyłanie żądań PUT, jak opisano w sekcji Krok 4.3. Wznów przesyłanie, aby przesłać kolejne fragmenty pliku, aż do przesłania całego pliku.

Gdy cały plik zostanie przesłany, serwer odpowie kodem odpowiedzi HTTP 201 (Created) i zwróci żądane części nowo utworzonego zasobu wideo.

Jeśli żądanie zostanie przerwane lub aplikacja otrzyma kod odpowiedzi 5xx, wykonaj czynności opisane w kroku 4, aby dokończyć przesyłanie. Zamiast próbować przesłać resztę pliku, kontynuuj przesyłanie fragmentów od miejsca, w którym zostało przerwane. Aby dowiedzieć się, gdzie wznowić przesyłanie pliku, sprawdź jego stan. Nie zakładaj, że serwer otrzymał wszystkie (lub żadne) bajty wysłane w poprzednim żądaniu.

Uwaga: możesz też poprosić o stan aktywnego przesyłania między przesłanymi fragmentami. (przesyłanie nie musi być przerwane, aby można było pobrać jego stan).