API Gmail позволяет загружать данные из файлов при создании или обновлении черновика , а также при вставке или отправке сообщения .
Варианты загрузки
API Gmail позволяет загружать определенные типы бинарных данных или медиафайлов. Конкретные характеристики загружаемых данных указаны на справочной странице для каждого метода, поддерживающего загрузку медиафайлов:
- Максимальный размер загружаемого файла : максимальный объем данных, который можно сохранить этим методом.
- Допустимые MIME-типы носителей : типы двоичных данных, которые можно хранить с помощью этого метода.
Вы можете отправлять запросы на загрузку любым из следующих способов. Укажите используемый метод с помощью параметра запроса uploadType .
- Простая загрузка :
uploadType=media. Для быстрой передачи небольших файлов, например, размером 5 МБ или меньше. - Многокомпонентная загрузка :
uploadType=multipart. Для быстрой передачи небольших файлов и метаданных; передает файл вместе с описывающими его метаданными в одном запросе. - Возобновляемая загрузка :
uploadType=resumable. Для надежной передачи, особенно важной для больших файлов. При этом методе используется запрос на инициацию сессии, который может дополнительно включать метаданные. Это хорошая стратегия для большинства приложений, поскольку она работает и для небольших файлов, но требует одного дополнительного HTTP-запроса на каждую загрузку.
При загрузке медиафайлов используется специальный URI. Фактически, методы, поддерживающие загрузку медиафайлов, имеют два конечных URI:
URI /upload используется для загрузки медиафайлов. Формат конечной точки загрузки — стандартный URI ресурса с префиксом «/upload». Используйте этот URI при передаче самих медиаданных.
Пример:
POST /upload/gmail/v1/users/ userId /messages/sendСтандартный URI ресурса для метаданных. Если ресурс содержит какие-либо поля данных, эти поля используются для хранения метаданных, описывающих загруженный файл. Вы можете использовать этот URI при создании или обновлении значений метаданных.
Пример:
POST /gmail/v1/users/ userId /messages/send
Простая загрузка
Самый простой способ загрузки файла — это отправка простого запроса на загрузку. Этот вариант хорошо подходит в следующих случаях:
- Размер файла достаточно мал, чтобы при сбое соединения его можно было загрузить целиком повторно.
- Метаданные для отправки отсутствуют. Это может быть так, если вы планируете отправить метаданные для этого ресурса в отдельном запросе, или если метаданные не поддерживаются или недоступны.
Для использования простой загрузки отправьте POST или PUT запрос к URI метода /upload и добавьте параметр запроса uploadType=media . Например:
POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=media
При выполнении простого запроса на загрузку следует использовать следующие HTTP-заголовки:
-
Content-Type. Установите один из типов данных медиафайлов, принимаемых методом загрузки, указанных в справочнике API. -
Content-Length. Установите значение, равное количеству загружаемых байтов. Не требуется, если вы используете кодирование с пошаговой передачей .
Пример: Простая загрузка
В следующем примере показано использование простого запроса на загрузку файла через API Gmail.
POST /upload/gmail/v1/users/userId/messages/send?uploadType=media HTTP/1.1 Host: www.googleapis.com Content-Type: message/rfc822 Content-Length: number_of_bytes_in_file Authorization: Bearer your_auth_token Email Message data
Если запрос выполнен успешно, сервер возвращает код состояния HTTP 200 OK вместе со всеми метаданными:
HTTP/1.1 200 Content-Type: application/json {
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": unsigned long,
"payload": {
"partId": string,
"mimeType": string,
"filename": string,
"headers": [
{
"name": string,
"value": string
}
],
"body": users.messages.attachments Resource,
"parts": [
(MessagePart)
]
},
"sizeEstimate": integer,
"raw": bytes
}
Многокомпонентная загрузка
Если вам необходимо отправить метаданные вместе с данными для загрузки, вы можете выполнить один multipart/related запрос. Это хороший вариант, если отправляемые данные достаточно малы, чтобы их можно было загрузить целиком повторно в случае сбоя соединения.
Для использования многокомпонентной загрузки отправьте POST или PUT запрос к URI метода /upload и добавьте параметр запроса uploadType=multipart , например:
POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=multipart
В качестве основных HTTP-заголовков для многокомпонентной загрузки следует использовать следующие:
-
Content-Type. Установите значение multipart/related и укажите разделительную строку, используемую для идентификации частей запроса. -
Content-Length. Установите значение, равное общему количеству байтов в теле запроса. Медиаконтент запроса должен быть меньше максимального размера файла, указанного для этого метода.
Тело запроса отформатировано как multipart/related тип контента [ RFC2387 ] и содержит ровно две части. Части идентифицируются разделительной строкой, а за последней разделительной строкой следуют два дефиса.
Каждая часть многокомпонентного запроса должна содержать дополнительный заголовок Content-Type :
- Метаданные: должны располагаться первыми, а
Content-Typeдолжен соответствовать одному из принятых форматов метаданных. - Часть, относящаяся к медиафайлам: должна быть указана второй, а
Content-Typeдолжен соответствовать одному из MIME-типов медиафайлов, принимаемых данным методом.
Для каждого метода см. справочник API, где указан список принимаемых MIME-типов медиафайлов и ограничения по размеру загружаемых файлов.
Примечание: Чтобы создать или обновить только раздел метаданных, без загрузки связанных данных, просто отправьте POST или PUT запрос к стандартной конечной точке ресурса: https://www.googleapis.com/gmail/v1/users/ userId /messages/send
Пример: Многокомпонентная загрузка
В приведенном ниже примере показан многокомпонентный запрос на загрузку данных через API Gmail.
POST /upload/gmail/v1/users/userId/messages/send?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 {
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": unsigned long,
"payload": {
"partId": string,
"mimeType": string,
"filename": string,
"headers": [
{
"name": string,
"value": string
}
],
"body": users.messages.attachments Resource,
"parts": [
(MessagePart)
]
},
"sizeEstimate": integer,
"raw": bytes
} --foo_bar_baz Content-Type: message/rfc822 Email Message data --foo_bar_baz--
Если запрос выполнен успешно, сервер возвращает код состояния HTTP 200 OK вместе со всеми метаданными:
HTTP/1.1 200 Content-Type: application/json {
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": unsigned long,
"payload": {
"partId": string,
"mimeType": string,
"filename": string,
"headers": [
{
"name": string,
"value": string
}
],
"body": users.messages.attachments Resource,
"parts": [
(MessagePart)
]
},
"sizeEstimate": integer,
"raw": bytes
}
Возобновляемая загрузка
Для более надежной загрузки файлов данных можно использовать протокол возобновляемой загрузки. Этот протокол позволяет возобновить операцию загрузки после сбоя связи, прервавшего поток данных. Он особенно полезен при передаче больших файлов, когда высока вероятность прерывания сети или другого сбоя передачи, например, при загрузке из мобильного приложения. Он также может снизить потребление полосы пропускания в случае сбоев сети, поскольку вам не нужно начинать загрузку больших файлов с самого начала.
Для использования функции возобновления загрузки необходимо выполнить следующие действия:
- Начните сеанс с возможностью возобновления загрузки . Выполните первоначальный запрос к URI загрузки, включающий метаданные, если таковые имеются.
- Сохраните URI возобновляемой сессии . Сохраните URI сессии, возвращенный в ответе на первоначальный запрос; вы будете использовать его для остальных запросов в этой сессии.
- Загрузите файл . Отправьте медиафайл на URI возобновляемой сессии.
Кроме того, приложения, использующие возобновляемую загрузку, должны иметь код для возобновления прерванной загрузки . Если загрузка прервана, необходимо определить, какой объем данных был успешно получен, и затем возобновить загрузку с этого момента.
Примечание: Срок действия URI для загрузки истекает через неделю.
Шаг 1: Запустите сессию с возможностью возобновления.
Для запуска возобновляемой загрузки отправьте POST или PUT запрос к URI метода /upload и добавьте параметр запроса uploadType=resumable , например:
POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=resumable
В первом запросе тело либо пустое, либо содержит только метаданные; фактическое содержимое файла, который вы хотите загрузить, будет передаваться в последующих запросах.
В первоначальном запросе используйте следующие HTTP-заголовки:-
X-Upload-Content-Type. Установите значение MIME-типа медиафайлов, которые будут передаваться в последующих запросах. -
X-Upload-Content-Length. Установите значение, равное количеству байтов данных для загрузки, которые будут переданы в последующих запросах. Если длина неизвестна на момент запроса, этот заголовок можно опустить. - Если предоставляются метаданные:
Content-Type. Устанавливается в соответствии с типом данных метаданных. -
Content-Length. Установите значение, равное количеству байтов, указанных в теле этого первоначального запроса. Не требуется, если вы используете кодирование с пошаговой передачей .
Для каждого метода см. справочник API, где указан список принимаемых MIME-типов медиафайлов и ограничения по размеру загружаемых файлов.
Пример: Запрос на возобновление сессии
В следующем примере показано, как инициировать возобновляемую сессию для API Gmail.
POST /upload/gmail/v1/users/userId/messages/send?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: message/rfc822 X-Upload-Content-Length: 2000000 {
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": unsigned long,
"payload": {
"partId": string,
"mimeType": string,
"filename": string,
"headers": [
{
"name": string,
"value": string
}
],
"body": users.messages.attachments Resource,
"parts": [
(MessagePart)
]
},
"sizeEstimate": integer,
"raw": bytes
}
Примечание: Для первоначального запроса на возобновление обновления без метаданных оставьте тело запроса пустым и установите заголовок 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/gmail/v1/users/userId/messages/send?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 байт для текущего примера.
PUT https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1 Content-Length: 2000000 Content-Type: message/rfc822 bytes 0-1999999
Если запрос выполнен успешно, сервер отвечает HTTP 201 Created , а также любыми метаданными, связанными с этим ресурсом. Если первоначальный запрос возобновляемой сессии был PUT для обновления существующего ресурса, то в ответе об успешном выполнении будет 200 OK , а также любые метаданные, связанные с этим ресурсом.
Если запрос на загрузку прерван или вы получили HTTP 503 Service Unavailable или любой другой ответ 5xx от сервера, выполните действия, описанные в разделе "Возобновить прерванную загрузку" .
Загрузка файла по частям.
При использовании возобновляемой загрузки вы можете разбить файл на фрагменты и отправить серию запросов на последовательную загрузку каждого фрагмента. Это не самый предпочтительный подход, поскольку дополнительные запросы связаны с производительностью, и обычно он не требуется. Однако вам может потребоваться использовать разбиение на фрагменты, чтобы уменьшить объем данных, передаваемых в одном запросе. Это полезно, когда существует фиксированный временной лимит для отдельных запросов, как это справедливо для некоторых классов запросов Google App Engine. Это также позволяет, например, отображать ход загрузки для устаревших браузеров, которые по умолчанию не поддерживают отображение хода загрузки.
Возобновить прерванную загрузку
Если запрос на загрузку прерывается до получения ответа или если вы получаете от сервера HTTP-запрос с ошибкой 503 Service Unavailable , вам необходимо возобновить прерванную загрузку. Для этого:
- Статус запроса. Чтобы узнать текущий статус загрузки, отправьте пустой
PUTзапрос на URI загрузки. В заголовке HTTP-запроса должен содержаться заголовокContent-Range, указывающий на то, что текущая позиция в файле неизвестна. Например, установитеContent-Rangeравным*/2000000если общая длина файла составляет 2 000 000 символов. Если полный размер файла неизвестен, установитеContent-Rangeравным*/*.Примечание: Вы можете запросить статус между фрагментами, а не только в случае прерывания загрузки. Это полезно, например, если вы хотите отображать индикаторы хода загрузки для устаревших браузеров.
- Получите количество загруженных байтов. Обработайте ответ на запрос состояния. Сервер использует заголовок
Rangeв своем ответе, чтобы указать, какие байты он уже получил. Например, заголовокRangeсо значением0-299999указывает на то, что получены первые 300 000 байтов файла. - Загрузите оставшиеся данные. Наконец, теперь, когда вы знаете, где возобновить запрос, отправьте оставшиеся данные или текущий фрагмент. Обратите внимание, что в любом случае оставшиеся данные необходимо рассматривать как отдельный фрагмент, поэтому при возобновлении загрузки необходимо отправить заголовок
Content-Range.
Пример: Возобновление прерванной загрузки
1) Запросите статус загрузки.
В следующем запросе используется заголовок Content-Range , указывающий на то, что текущая позиция в файле размером 2 000 000 байт неизвестна.
PUT {session_uri} HTTP/1.1
Content-Length: 0
Content-Range: bytes */20000002) Извлеките из ответа количество уже загруженных байтов.
В ответе сервера заголовок 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при возобновляемой загрузке осуществляется путем начала всей загрузки с самого начала.
Экспоненциальная задержка
Экспоненциальная задержка — это стандартная стратегия обработки ошибок в сетевых приложениях, при которой клиент периодически повторяет неудачный запрос в течение увеличивающегося промежутка времени. Если большой объем запросов или интенсивный сетевой трафик приводят к тому, что сервер возвращает ошибки, экспоненциальная задержка может быть хорошей стратегией для обработки этих ошибок. И наоборот, она не подходит для обработки ошибок, не связанных с объемом сети или временем ответа, таких как недействительные учетные данные авторизации или ошибки «файл не найден».
При правильном использовании экспоненциальная задержка повышает эффективность использования полосы пропускания, сокращает количество запросов, необходимых для получения успешного ответа, и максимизирует пропускную способность запросов в средах с параллельным выполнением.
Процесс реализации простой экспоненциальной задержки выглядит следующим образом:
- Отправьте запрос к API.
- Получен
HTTP 503, указывающий на необходимость повторной отправки запроса. - Подождите 1 секунду + случайное число миллисекунд и повторите запрос.
- Получен
HTTP 503, указывающий на необходимость повторной отправки запроса. - Подождите 2 секунды + случайное число миллисекунд и повторите запрос.
- Получен
HTTP 503, указывающий на необходимость повторной отправки запроса. - Подождите 4 секунды + случайное число миллисекунд и повторите запрос.
- Получен
HTTP 503, указывающий на необходимость повторной отправки запроса. - Подождите 8 секунд + случайное число миллисекунд и повторите запрос.
- Получен
HTTP 503, указывающий на необходимость повторной отправки запроса. - Подождите 16 секунд + случайное число миллисекунд и повторите запрос.
- Стоп. Сообщите об ошибке или зарегистрируйте её.
В описанном выше алгоритме random_number_milliseconds — это случайное число миллисекунд, меньшее или равное 1000. Это необходимо, поскольку введение небольшой случайной задержки помогает более равномерно распределить нагрузку и избежать перегрузки сервера. Значение random_number_milliseconds необходимо переопределять после каждого ожидания.
Примечание: время ожидания всегда равно (2 ^ n) + случайное число миллисекунд, где n — монотонно возрастающее целое число, изначально равное 0. Целое число n увеличивается на 1 на каждой итерации (каждом запросе).
Алгоритм настроен на завершение работы, когда n равно 5. Это ограничение предотвращает бесконечные повторные попытки клиентов и приводит к общей задержке около 32 секунд, прежде чем запрос будет признан «неисправимой ошибкой». Большее максимальное количество повторных попыток допустимо, особенно если выполняется длительная загрузка; просто убедитесь, что задержка повторных попыток ограничена разумным значением, например, менее одной минуты.