Загрузка файлов

API разработчика Google Play позволяет загружать изображения , APK-файлы или файлы расширения для редактирования . Ниже мы используем изображения в качестве примера.

Варианты загрузки

API разработчика Google Play позволяет загружать определенные типы двоичных данных или мультимедиа. Конкретные характеристики данных, которые вы можете загрузить, указаны на справочной странице для любого метода, поддерживающего загрузку мультимедиа:

  • Максимальный размер загружаемого файла : максимальный объем данных, который вы можете сохранить с помощью этого метода.
  • Допустимые типы MIME мультимедиа : типы двоичных данных, которые вы можете хранить с помощью этого метода.

Вы можете отправлять запросы на загрузку любым из следующих способов. Укажите используемый метод с помощью параметра запроса uploadType .

  • Простая загрузка : uploadType=media . Для быстрой передачи файлов меньшего размера, например, 5 МБ и меньше.
  • Многочастная загрузка : uploadType=multipart . Для быстрой передачи небольших файлов и метаданных; передает файл вместе с метаданными, которые его описывают, и все это в одном запросе.
  • Возобновляемая загрузка : uploadType=resumable . Для надежной передачи, особенно важно для файлов большего размера. С помощью этого метода вы используете запрос, инициирующий сеанс, который при необходимости может включать метаданные. Это хорошая стратегия для большинства приложений, поскольку она также работает для файлов меньшего размера за счет одного дополнительного HTTP-запроса на каждую загрузку.

Когда вы загружаете медиафайлы, вы используете специальный URI. Фактически методы, поддерживающие загрузку мультимедиа, имеют две конечные точки URI:

  • URI /upload для мультимедиа. Формат конечной точки загрузки — стандартный URI ресурса с префиксом «/upload». Используйте этот URI при передаче самих медиаданных.

    Пример: POST /upload/androidpublisher/v3/applications/ packageName /edits/ editId /listings/ language / imageType

  • Стандартный URI ресурса для метаданных. Если ресурс содержит какие-либо поля данных, эти поля используются для хранения метаданных, описывающих загруженный файл. Этот URI можно использовать при создании или обновлении значений метаданных.

    Пример: POST /androidpublisher/v3/applications/ packageName /edits/ editId /listings/ language / imageType

Простая загрузка

Самый простой способ загрузить файл — это сделать простой запрос на загрузку. Этот вариант является хорошим выбором, если:

  • Файл достаточно мал, чтобы его можно было загрузить снова целиком в случае сбоя соединения.
  • Нет метаданных для отправки. Это может быть правдой, если вы планируете отправлять метаданные для этого ресурса в отдельном запросе или если метаданные не поддерживаются и не доступны.

Чтобы использовать простую загрузку, выполните запрос POST или PUT к URI метода /upload и добавьте параметр запроса uploadType=media . Например:

POST https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=media

Заголовки HTTP, используемые при выполнении простого запроса на загрузку, включают:

Пример: Простая загрузка

В следующем примере показано использование простого запроса на загрузку для API разработчика Google Play.

POST /upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=media HTTP/1.1
Host: www.googleapis.com
Content-Type: image/png
Content-Length: number_of_bytes_in_file
Authorization: Bearer your_auth_token

PNG data

Если запрос успешен, сервер возвращает код состояния HTTP 200 OK вместе со всеми метаданными:

HTTP/1.1 200
Content-Type: application/json

{
 
"image": {
   
"id": string,
   
"url": string,
   
"sha1": string
 
}
}

Многочастная загрузка

Если у вас есть метаданные, которые вы хотите отправить вместе с данными для загрузки, вы можете сделать один multipart/related запрос. Это хороший выбор, если отправляемые вами данные достаточно малы, чтобы их можно было загрузить снова целиком в случае сбоя соединения.

Чтобы использовать многочастную загрузку, выполните запрос POST или PUT к URI метода /upload и добавьте параметр запроса uploadType=multipart , например:

POST https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=multipart

HTTP-заголовки верхнего уровня, которые следует использовать при выполнении запроса на многочастную загрузку, включают:

  • Content-Type . Установите значение «многочастный/связанный» и включите граничную строку, которую вы используете для идентификации частей запроса.
  • Content-Length . Устанавливается общее количество байтов в теле запроса. Медиа-часть запроса должна быть меньше максимального размера файла, указанного для этого метода.

Тело запроса отформатировано как multipart/related тип контента [ RFC2387 ] и содержит ровно две части. Части идентифицируются граничной строкой, а за последней граничной строкой следуют два дефиса.

Для каждой части составного запроса требуется дополнительный заголовок Content-Type :

  1. Часть метаданных: должна идти первой, а Content-Type должен соответствовать одному из принятых форматов метаданных.
  2. Медиа-часть: должна стоять на втором месте, а Content-Type должен соответствовать одному из принятых методом медиа-типов MIME.

Список допустимых типов MIME мультимедиа и ограничения на размер загружаемых файлов для каждого метода см. в справочнике по API.

Примечание. Чтобы создать или обновить только часть метаданных, не загружая связанные данные, просто отправьте запрос POST или PUT в конечную точку стандартного ресурса: https://www.googleapis.com/androidpublisher/v3/applications/ packageName /edits/ editId /listings/ language / imageType

Пример: многочастная загрузка

В приведенном ниже примере показан многочастный запрос на загрузку для API разработчика Google Play.

POST /upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?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

{
 
"image": {
   
"id": string,
   
"url": string,
   
"sha1": string
 
}
} --foo_bar_baz Content-Type: image/png PNG data --foo_bar_baz--

Если запрос успешен, сервер возвращает код состояния HTTP 200 OK вместе со всеми метаданными:

HTTP/1.1 200
Content-Type: application/json

{
 
"image": {
   
"id": string,
   
"url": string,
   
"sha1": string
 
}
}

Возобновляемая загрузка

Для более надежной загрузки файлов данных вы можете использовать протокол возобновляемой загрузки. Этот протокол позволяет возобновить операцию загрузки после того, как сбой связи прервал поток данных. Это особенно полезно, если вы передаете большие файлы и высока вероятность сбоя сети или какого-либо другого сбоя передачи, например, при загрузке из мобильного клиентского приложения. Это также может снизить использование полосы пропускания в случае сбоев сети, поскольку вам не придется перезапускать загрузку больших файлов с самого начала.

Шаги по использованию возобновляемой загрузки включают в себя:

  1. Запустите возобновляемый сеанс . Сделайте первоначальный запрос к URI загрузки, который включает метаданные, если таковые имеются.
  2. Сохраните URI возобновляемого сеанса . Сохраните URI сеанса, возвращенный в ответе на первоначальный запрос; вы будете использовать его для остальных запросов в этом сеансе.
  3. Загрузите файл . Отправьте медиафайл по URI возобновляемого сеанса.

Кроме того, приложения, использующие возобновляемую загрузку, должны иметь код для возобновления прерванной загрузки . Если загрузка прервана, выясните, какой объем данных был успешно получен, а затем возобновите загрузку, начиная с этого момента.

Примечание. Срок действия URI загрузки истекает через неделю.

Шаг 1. Запустите возобновляемый сеанс.

Чтобы инициировать возобновляемую загрузку, выполните запрос POST или PUT к URI метода /upload и добавьте параметр запроса uploadType=resumable , например:

POST https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=resumable

Для этого инициирующего запроса тело либо пусто, либо содержит только метаданные; вы будете передавать фактическое содержимое файла, который хотите загрузить, в последующих запросах.

Используйте следующие HTTP-заголовки с первоначальным запросом:

  • X-Upload-Content-Type . Установите тип MIME мультимедиа для загружаемых данных, которые будут передаваться в последующих запросах.
  • X-Upload-Content-Length . Установите количество байтов загружаемых данных, которые будут переданы в последующих запросах. Если длина неизвестна на момент этого запроса, вы можете опустить этот заголовок.
  • Если предоставляются метаданные: Content-Type . Устанавливается в соответствии с типом данных метаданных.
  • Content-Length . Установите количество байтов, указанное в теле этого первоначального запроса. Не требуется, если вы используете фрагментированное кодирование передачи .

Список допустимых типов MIME мультимедиа и ограничения на размер загружаемых файлов для каждого метода см. в справочнике по API.

Пример: запрос на инициирование возобновляемого сеанса

В следующем примере показано, как инициировать возобновляемый сеанс для API разработчика Google Play.

POST /upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?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/png
X-Upload-Content-Length: 2000000

{
 
"image": {
   
"id": string,
   
"url": string,
   
"sha1": string
 
}
}

Примечание. Для первоначального возобновляемого запроса на обновление без метаданных оставьте тело запроса пустым и установите для заголовка Content-Length значение 0 .

В следующем разделе описывается, как обрабатывать ответ.

Шаг 2. Сохраните URI возобновляемого сеанса.

Если запрос на инициацию сеанса успешен, сервер API отвечает кодом состояния HTTP 200 OK . Кроме того, он предоставляет заголовок Location , который указывает URI возобновляемого сеанса. Заголовок Location , показанный в примере ниже, включает часть параметра запроса upload_id , которая дает уникальный идентификатор загрузки, который будет использоваться для этого сеанса.

Пример: ответ на инициацию возобновляемого сеанса

Вот ответ на запрос на шаге 1:

HTTP/1.1 200 OK
Location: https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2
Content-Length: 0

Значение заголовка Location , как показано в приведенном выше примере ответа, — это URI сеанса, который вы будете использовать в качестве конечной точки HTTP для фактической загрузки файла или запроса статуса загрузки.

Скопируйте и сохраните URI сеанса, чтобы использовать его для последующих запросов.

Шаг 3. Загрузите файл.

Чтобы загрузить файл, отправьте запрос PUT на URI загрузки, полученный на предыдущем шаге. Формат запроса на загрузку:

PUT session_uri

Заголовки HTTP, используемые при выполнении запросов на возобновляемую загрузку файлов, включают Content-Length . Установите это количество байтов, которые вы загружаете в этом запросе, что обычно соответствует размеру загружаемого файла.

Пример: запрос на возобновляемую загрузку файла

Вот возобновляемый запрос на загрузку всего 2 000 000 байт PNG-файла для текущего примера.

PUT https://www.googleapis.com/upload/androidpublisher/v3/applications/packageName/edits/editId/listings/language/imageType?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1
Content-Length: 2000000
Content-Type: image/png

bytes 0-1999999

Если запрос успешен, сервер отвечает HTTP 201 Created вместе со всеми метаданными, связанными с этим ресурсом. Если первоначальный запрос возобновляемого сеанса был PUT для обновления существующего ресурса, успешный ответ будет 200 OK вместе со всеми метаданными, связанными с этим ресурсом.

Если запрос на загрузку прерван или вы получили сообщение HTTP 503 Service Unavailable или любой другой ответ 5xx от сервера, выполните процедуру, описанную в разделе «Возобновление прерванной загрузки» .


Загрузка файла частями

Благодаря возобновляемым загрузкам вы можете разбить файл на фрагменты и отправить серию запросов для последовательной загрузки каждого фрагмента. Это не предпочтительный подход, поскольку дополнительные запросы связаны с затратами на производительность, и обычно в этом нет необходимости. Однако вам может потребоваться использовать фрагментирование, чтобы уменьшить объем данных, передаваемых в любом отдельном запросе. Это полезно, когда для отдельных запросов установлен фиксированный лимит времени, как это справедливо для определенных классов запросов Google App Engine. Он также позволяет вам выполнять такие действия, как предоставление индикаторов хода загрузки для устаревших браузеров, которые по умолчанию не имеют поддержки процесса загрузки.


Возобновить прерванную загрузку

Если запрос на загрузку прерван до получения ответа или если вы получили ответ HTTP 503 Service Unavailable от сервера, вам необходимо возобновить прерванную загрузку. Для этого:

  1. Статус запроса. Запросите текущий статус загрузки, отправив пустой запрос PUT к URI загрузки. Для этого запроса заголовки HTTP должны включать заголовок Content-Range , указывающий, что текущая позиция в файле неизвестна. Например, установите Content-Range на */2000000 если общая длина файла составляет 2 000 000. Если вы не знаете полный размер файла, установите для 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 . Эти ошибки могут возникнуть, если сервер перегружен. Экспоненциальная отсрочка может помочь смягчить такого рода проблемы в периоды большого объема запросов или интенсивного сетевого трафика.
  • Другие типы запросов не должны обрабатываться экспоненциальной задержкой, но вы все равно можете повторить некоторые из них. При повторной попытке этих запросов ограничьте количество повторных попыток. Например, ваш код может ограничить десять или менее попыток, прежде чем сообщать об ошибке.
  • Обрабатывайте ошибки 404 Not Found и 410 Gone при возобновлении загрузки, начиная всю загрузку с самого начала.

Экспоненциальный откат

Экспоненциальная отсрочка — это стандартная стратегия обработки ошибок для сетевых приложений, при которой клиент периодически повторяет неудачный запрос в течение увеличивающегося промежутка времени. Если из-за большого объема запросов или интенсивного сетевого трафика сервер возвращает ошибки, экспоненциальная отсрочка может быть хорошей стратегией для обработки этих ошибок. И наоборот, это неподходящая стратегия для устранения ошибок, не связанных с объемом сети или временем ответа, таких как неверные учетные данные авторизации или ошибки «файл не найден».

При правильном использовании экспоненциальная отсрочка повышает эффективность использования полосы пропускания, уменьшает количество запросов, необходимых для получения успешного ответа, и максимизирует пропускную способность запросов в параллельных средах.

Порядок реализации простого экспоненциального отката следующий:

  1. Сделайте запрос к API.
  2. Получите ответ HTTP 503 , который указывает, что вам следует повторить запрос.
  3. Подождите 1 секунду + случайное_число_миллисекунд и повторите запрос.
  4. Получите ответ HTTP 503 , который указывает, что вам следует повторить запрос.
  5. Подождите 2 секунды + случайное_число_миллисекунд и повторите запрос.
  6. Получите ответ HTTP 503 , который указывает, что вам следует повторить запрос.
  7. Подождите 4 секунды + случайное_число_миллисекунд и повторите запрос.
  8. Получите ответ HTTP 503 , который указывает, что вам следует повторить запрос.
  9. Подождите 8 секунд + случайное_число_миллисекунд и повторите запрос.
  10. Получите ответ HTTP 503 , который указывает, что вам следует повторить запрос.
  11. Подождите 16 секунд + случайное_число_миллисекунд и повторите запрос.
  12. Останавливаться. Сообщите или зарегистрируйте ошибку.

В приведенном выше потоке случайное_число_миллисекунды — это случайное число миллисекунд, меньшее или равное 1000. Это необходимо, поскольку введение небольшой случайной задержки помогает распределить нагрузку более равномерно и избежать возможности затормозить сервер. Значение Random_number_milli Seconds необходимо переопределять после каждого ожидания.

Примечание. Ожидание всегда равно (2 ^ n) + случайное_число_миллисекунд, где n — монотонно увеличивающееся целое число, изначально определенное как 0. Целое число n увеличивается на 1 для каждой итерации (каждого запроса).

Алгоритм настроен на завершение, когда n равно 5. Этот предел не позволяет клиентам бесконечно повторять попытки и приводит к общей задержке около 32 секунд, прежде чем запрос будет считаться «неустранимой ошибкой». Большее максимальное количество повторов допустимо, особенно если идет длительная загрузка; просто не забудьте ограничить задержку повторной попытки чем-то разумным, скажем, менее одной минуты.

Руководства по клиентской библиотеке API