Uploads retomáveis

Você pode enviar vídeos de maneira mais confiável usando o protocolo de upload retomável para APIs do Google. Este protocolo permite que você retome uma operação de upload após uma interrupção de rede ou outra falha de transmissão, economizando tempo e largura de banda em caso de falhas na rede.

Usar uploads retomáveis é especialmente útil em um dos seguintes casos:

  • Você está transferindo arquivos grandes.
  • A probabilidade de uma interrupção de rede é elevada.
  • Uploads provenientes de um dispositivo com baixa largura de banda ou conexão de internet instável, como um dispositivo móvel.

Este guia explica a sequência de solicitações HTTP que um aplicativo faz para fazer upload de vídeos utilizando um processo de upload retomável. Destina-se primariamente a desenvolvedores que não conseguem utilizar as bibliotecas de clientes de API do Google, algumas das quais oferecem suporte nativo para a retomada de envios. Na verdade, o guia API de dados do YouTube - upload de um vídeo explica como usar a Biblioteca de clientes de APIs do Google para Python para enviar um vídeo usando um processo de upload retomável.

Observação: você também pode ver a série de solicitações feitas para os uploads retomáveis ou qualquer outra operação de API usando uma das bibliotecas de cliente API do Google com registro HTTPS ativado. Por exemplo, para ativar o trace HTTP para Python, use a biblioteca httplib2:

httplib2.debuglevel = 4

Passo 1 - Iniciar uma sessão retomável

Para iniciar o upload retomável de vídeos, envie uma solicitação POST ao URL a seguir. No URL, defina o valor do parâmetro part como o valor apropriado para sua solicitação. Lembre-se de que o valor do parâmetro identifica as partes que contêm as propriedades que você define, além de identificar as partes que você quer que a resposta da API inclua. Os valores de parâmetro no URL da solicitação precisam ser codificados em URL.

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

Defina o corpo da solicitação como um recurso video. Defina também os seguintes cabeçalhos de solicitação HTTP:

  • Authorization: o token de autorização para a solicitação.
  • Content-Length: o número de bytes fornecidos no corpo da solicitação. Não é necessário informar esse cabeçalho se você usa a codificação de transferência fragmentada.
  • Content-Type: define o valor como application/json; charset=UTF-8.
  • X-Upload-Content-Length: o número de bytes que serão enviados em solicitações subsequentes. Defina este valor para o tamanho do arquivo que você está enviando.
  • x-upload-content-type: o tipo MIME do arquivo que você está enviando. É possível fazer upload de arquivos com qualquer tipo MIME de vídeo (video/*) ou um tipo MIME de application/octet-stream.

O exemplo a seguir mostra como iniciar uma sessão retomável para enviar um vídeo. A solicitação define (e recupera) propriedades nas partes snippet e status do recurso video, além de recuperar propriedades na parte contentdetails do recurso.

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

O exemplo a seguir mostra uma solicitação POST que tem todos esses valores preenchidos, com exceção do token de autenticação. O valor categoryId no exemplo corresponde a uma categoria de vídeo. A lista de categorias compatíveis pode ser recuperada usando o método videoCategories.list da 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"
  }
}

Passo 2 - Salvar o URI da sessão retomável

Se a solicitação for bem-sucedida, o servidor de API vai responder com um código de status HTTP 200 (OK), e a resposta incluirá um cabeçalho HTTP Location que especifica o URI da sessão retomável. Esse é o URI que você usará para fazer o upload de seu arquivo de vídeo.

O exemplo abaixo mostra um exemplo de resposta de API para a solicitação no passo 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

Passo 3 - Upload do arquivo de vídeo

Depois de extrair o URI de sessão da resposta da API, você precisará fazer upload do conteúdo do arquivo de vídeo real para esse local. O corpo da solicitação é o conteúdo do arquivo binário para o vídeo que você está carregando. O exemplo abaixo mostra o formato da solicitação.

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

BINARY_FILE_DATA

A solicitação define os seguintes cabeçalhos de solicitação HTTP:

  • Authorization: o token de autorização para a solicitação.
  • Content-Length: o tamanho do arquivo que você está enviando. Esse valor precisa ser igual ao valor do cabeçalho da solicitação HTTP X-Upload-Content-Length na etapa 1.
  • Content-Type: o tipo MIME do arquivo que você está enviando. Esse valor precisa ser igual ao valor do cabeçalho da solicitação HTTP X-Upload-Content-Type na etapa 1.

Passo 4 - Concluir o processo de upload

Sua solicitação levará a um dos seguintes cenários:

  • O upload foi concluído.

    O servidor de API responde com um código de resposta HTTP 201 (Created). O corpo da resposta é o recurso video que você criou.

  • O upload não foi concluído, mas pode ser retomado.

    Você conseguirá retomar um upload em um dos seguintes casos:

    • Sua solicitação é interrompida porque a conexão entre seu aplicativo e o servidor de API está perdida. Neste caso, você não receberá uma resposta da API.

    • A resposta da API especifica qualquer um dos seguintes códigos de resposta 5xx. Seu código deve usar uma estratégia de espera exponencial ao retomar uploads depois de receber qualquer um desses códigos de resposta.

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

    Para retomar um upload, siga as instruções para verificar o status do upload e retomar um upload abaixo. Lembre-se de que cada URI de sessão retomável tem uma vida finita e expira. Por isso, recomendamos iniciar um upload retomável assim que você receber o URI de sessão e retomar um upload interrompido logo após a interrupção.

  • Falha no upload.

    Para uma falha de upload, a resposta contém uma resposta de erro que ajuda a explicar a causa da falha. Para um upload que falha de forma permanente, a resposta da API terá um código de resposta 4xx ou 5xx diferente dos listados acima.

    Se você enviar uma solicitação com um URI de sessão expirado, o servidor retornará um código de resposta HTTP 404 (Not Found). Nesse caso, será necessário iniciar um novo upload retomável, conseguir um novo URI de sessão e iniciar o upload desde o início usando o novo URI.

Passo 4.1: verificar o status de um upload

Para verificar o status de um upload retomável interrompido, envie uma solicitação PUT vazia para o URL de upload que você recuperou na etapa 2 e também usou na etapa 3. Na solicitação, defina o valor do cabeçalho Content-Range como bytes */CONTENT_LENGTH, em que CONTENT_LENGTH é o tamanho do arquivo que você está enviando.

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

Passo 4.2: processar a resposta da API

Se o upload já foi concluído, independentemente de ter sido bem-sucedido ou ter falhado, a API retornará a mesma resposta enviada quando o upload foi originalmente concluído.

No entanto, se o upload tiver sido interrompido ou ainda estiver em andamento, a resposta da API terá um código de resposta HTTP 308 (Resume Incomplete). Na resposta, o cabeçalho Range especifica quantos bytes do arquivo já foram enviados.

  • O valor do cabeçalho é indexado a partir de 0 Dessa forma, um valor de cabeçalho de 0-999999 indica que os primeiros 1,000,000 bytes do arquivo foram enviados.
  • Se nada tiver sido enviado ainda, a resposta da API não incluirá o cabeçalho Range.

A resposta de exemplo abaixo mostra o formato de uma resposta da API para um upload retomável:

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

Se a resposta da API também incluir o cabeçalho Retry-After, use o valor desse cabeçalho para determinar quando tentar retomar o upload.

Passo 4.3: retomar o upload

Para retomar o upload, envie outra solicitação PUT para o URL de upload capturado no passo 2. Defina o corpo da solicitação para o código binário para a parte do arquivo de vídeo que ainda não foi enviada.

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

Você precisa definir os seguintes cabeçalhos de solicitação HTTP:

  • Authorization: o token de autorização para a solicitação.

  • Content-Length – O tamanho, em bytes, do conteúdo que ainda não foi enviado. Se você estiver fazendo upload do restante de um arquivo, poderá calcular esse valor subtraindo o valor FIRST_BYTE do TOTAL_CONTENT_LENGTH. Ambos os valores são usados no cabeçalho Content-Range.

  • Content-Range: a parte do arquivo que você está enviando. O valor do cabeçalho é composto por três valores:

    • FIRST_BYTE - O índice numérico baseado em 0 do número de bytes a partir do qual você está retomando o upload. Esse valor é um número maior que o segundo número no cabeçalho Range recuperado na etapa anterior. No exemplo anterior, o valor do cabeçalho Range era 0-999999, portanto, o primeiro byte em um próximo upload retomado seria 1000000.

    • LAST_BYTE - O índice numérico baseado em 0 do último byte do arquivo binário que você estiver enviando. Normalmente, este é o último byte no arquivo. Por exemplo, se o tamanho do arquivo for 3000000 bytes, o último byte no arquivo será o número 2999999.

    • TOTAL_CONTENT_LENGTH - O tamanho total do arquivo de vídeo em bytes. Esse valor é o mesmo que o cabeçalho Content-Length especificado na solicitação de upload original.

    Observação: você não pode fazer upload de um bloco não contínuo do arquivo binário. Se você tentar fazer upload de um bloco não contínuo, nada do conteúdo binário restante será enviado.

    Dessa forma, o primeiro byte enviado em um upload retomado deve ser o próximo byte após o último byte enviado ao YouTube. Veja a discussão do cabeçalho Range na etapa 4.2.

    Portanto, se o último byte no cabeçalho Range for 999999, o primeiro byte na solicitação para retomar o upload vai precisar ser o byte 1.000.000. (os dois números usam um índice baseado em 0). Se você tentar retomar o upload a partir do byte 999.999 ou inferior (sobrepondo bytes) ou a partir do byte 1.000.001 ou superior (pulando bytes), nenhum dos conteúdos binários será enviado.

Fazer upload de um arquivo em partes

Em vez de tentar fazer upload de um arquivo inteiro e retomar o upload em caso de interrupção da rede, o aplicativo pode quebrar o arquivo em partes e enviar uma série de solicitações para fazer upload dessas partes em sequência. Esta abordagem raramente é necessária e, na realidade, não indicada, visto que ela requer solicitações adicionais, que têm implicações de desempenho. No entanto, ela pode ser útil se você estiver tentando exibir um indicador de progresso em uma rede muito instável.

As instruções para upload de um arquivo em partes são praticamente idênticas ao processo de quatro passos explicado anteriormente neste guia. No entanto, as solicitações para começar a fazer upload de um arquivo (etapa 3 acima) e retomar o upload (etapa 4.3 acima) definem os valores do cabeçalho Content-Length e Content-Range de maneira diferente quando um arquivo está sendo enviado em partes.

  • O valor do cabeçalho Content-Length especifica o tamanho do bloco que a solicitação está enviando. Observe as seguintes restrições sobre os tamanhos da parte:

    • O tamanho da parte precisa ser um múltiplo de 256 KB. Essa restrição não se aplica à última parte, já que o tamanho do arquivo inteiro pode não ser um múltiplo de 256 KB. Lembre-se de que as partes maiores são mais eficientes.

    • O tamanho da parte deve ser igual para cada solicitação na sequência de upload, com exceção da última solicitação, que especifica o tamanho da parte final.

  • O cabeçalho Content-Range especifica os bytes no arquivo que a solicitação está enviando. As instruções para definir o cabeçalho Content-Range na etapa 4.3 são aplicáveis ao definir esse valor.

    Por exemplo, um valor de bytes 0-524287/2000000 mostra que a solicitação está enviando os primeiros 524.288 bytes (256 x 2.048) em um arquivo de 2 milhões de bytes.

O exemplo abaixo mostra o formato da primeira de uma série de solicitações que enviará um arquivo de 2.000.000 bytes em partes:

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}

Se uma solicitação diferente da solicitação final for concluída, o servidor de API vai responder com uma resposta 308 (Resume Incomplete). O formato da resposta será igual ao descrito na Etapa 4.2: processar a resposta da API acima.

Use o valor superior retornado no cabeçalho Range da resposta da API para determinar onde iniciar a próxima parte. Continue a enviar solicitações PUT, conforme descrito na Etapa 4.3: retomar o upload, para fazer upload de partes de arquivos subsequentes até que todo o arquivo tenha sido enviado.

Quando todo o arquivo for enviado por upload, o servidor responderá com um código de resposta HTTP 201 (Created) e retornará as partes solicitadas do recurso de vídeo recém-criado.

Se alguma solicitação for interrompida ou seu aplicativo receber algum código de resposta 5xx, siga o procedimento explicado na Etapa 4 para concluir o upload. Porém, em vez de tentar fazer upload do restante do arquivo, basta continuar fazendo upload das partes a partir do ponto em que você está retomando o upload. Use a verificação do status do upload para determinar em que ponto o upload do arquivo será retomado. Não pressuponha que o servidor recebeu todos os bytes (ou nenhum deles) enviados na solicitação anterior.

Observação: você também pode solicitar o status de um upload ativo entre partes carregadas (o upload não precisa ter sido interrompido para que você possa recuperar seu status).