Gmail API позволяет загружать данные файлов при создании или обновлении черновика, а также при вставке или отправке сообщения.
Варианты загрузки
Gmail API позволяет загружать определенные типы двоичных данных или медиафайлов. Особенности данных, которые можно загружать, указаны на справочной странице для каждого метода, поддерживающего загрузку медиаконтента:
- Максимальный размер загружаемого файла. Максимальный объем данных, который можно хранить при использовании этого метода.
- Допустимые 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. Укажите количество загружаемых байтов. Не требуется, если вы используете поблочное кодирование передачи.
Пример: простая загрузка
В примере ниже показано, как использовать простой запрос на загрузку для Gmail API.
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-типов, поддерживаемых методом.
Список допустимых MIME-типов медиаконтента и ограничения на размер загружаемых файлов для каждого метода можно найти в документации по API.
Примечание. Чтобы создать или обновить только метаданные, не загружая связанные с ними данные, отправьте запрос POST или PUT к стандартной конечной точке ресурса:
https://www.googleapis.com/gmail/v1/users/userId/messages/send
Пример: составная загрузка
Ниже приведен пример запроса на составную загрузку для Gmail API.
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. Укажите количество байтов, предоставленных в теле этого начального запроса. Не требуется, если вы используете поблочное кодирование передачи.
Список допустимых MIME-типов медиаконтента и ограничения на размер загружаемых файлов для каждого метода можно найти в документации по API.
Пример запроса на инициацию возобновляемого сеанса
В примере ниже показано, как инициировать возобновляемый сеанс для Gmail API.
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 сеанса, чтобы использовать его для последующих запросов.
Загрузите видео на YouTube
Чтобы загрузить файл, отправьте запрос 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, указывающий, что текущая позиция в файле неизвестна. Например, если общий размер файла составляет 2 000 000, задайте для параметраContent-Rangeзначение*/2000000. Если вы не знаете полный размер файла, задайте для параметра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 Error502 Bad Gateway503 Service Unavailable504 Gateway Timeout
- Если при возобновлении или повторной отправке запросов на загрузку возвращается ошибка сервера
5xx, используйте стратегию экспоненциальной выдержки. Такие ошибки могут возникать, если сервер перегружен. Экспоненциальная выдержка помогает справиться с такими проблемами в периоды большого объема запросов или высокой загрузки сети. - Для других типов запросов экспоненциальная выдержка не используется, но вы можете повторить некоторые из них. При повторной отправке таких запросов ограничьте количество попыток. Например, можно ограничить количество попыток десятью, а затем сообщать об ошибке.
- При возникновении ошибок
404 Not Foundи410 Goneво время возобновляемой загрузки начните загрузку заново.
Экспоненциальная задержка
Экспоненциальная выдержка – это стандартная стратегия обработки ошибок для сетевых приложений, при которой клиент периодически повторяет неудачный запрос в течение увеличивающегося периода времени. Если сервер возвращает ошибки из-за большого объема запросов или высокой загрузки сети, экспоненциальная выдержка может быть хорошей стратегией для обработки этих ошибок. Однако этот подход не подходит для устранения ошибок, не связанных с объемом сетевого трафика или временем ответа, например ошибок, связанных с недействительными учетными данными для авторизации или отсутствием файла.
При правильном использовании экспоненциальная выдержка повышает эффективность использования пропускной способности, снижает количество запросов, необходимых для получения успешного ответа, и максимизирует пропускную способность запросов в параллельных средах.
Простая экспоненциальная выдержка реализуется следующим образом:
- Выполняется запрос к API.
- Получите ответ
HTTP 503, который указывает, что запрос нужно повторить. - Подождите 1 секунду + random_number_milliseconds и повторите запрос.
- Получите ответ
HTTP 503, который указывает, что запрос нужно повторить. - Подождите 2 секунды + random_number_milliseconds и повторите запрос.
- Получите ответ
HTTP 503, который указывает, что запрос нужно повторить. - Подождите 4 секунды + random_number_milliseconds и повторите запрос.
- Получите ответ
HTTP 503, который указывает, что запрос нужно повторить. - Подождите 8 секунд + случайное число миллисекунд и повторите запрос.
- Получите ответ
HTTP 503, который указывает, что запрос нужно повторить. - Подождите 16 секунд + random_number_milliseconds и повторите запрос.
- Останови. Сообщите об ошибке или зарегистрируйте ее.
В приведенном выше примере random_number_milliseconds – это случайное число миллисекунд, не превышающее 1000. Это необходимо, поскольку небольшая случайная задержка помогает более равномерно распределить нагрузку и избежать перегрузки сервера. Значение random_number_milliseconds необходимо переопределять после каждого ожидания.
Примечание. Время ожидания всегда рассчитывается по формуле (2 ^ n) + случайное_число_миллисекунд, где n – монотонно возрастающее целое число, изначально равное 0. Целое число n увеличивается на 1 при каждой итерации (каждом запросе).
По умолчанию выполнение алгоритма прекращается при n=5, которое соответствует общей задержке около 32 с. Это ограничение не позволяет клиентам повторять попытки бесконечно и приводит к общей задержке около 32 секунд, прежде чем запрос будет считаться "неустранимой ошибкой". Максимальное количество попыток может быть и больше, особенно если загрузка занимает много времени. Однако задержка между попытками не должна быть слишком большой, например не более одной минуты.