Ваша серверная среда и FCM
Серверная часть Firebase Cloud Messaging состоит из двух компонентов:
- Серверная часть FCM предоставлена Google.
- Ваш сервер приложений или другая доверенная серверная среда, в которой работает логика вашего сервера, например облачные функции для Firebase или другие облачные среды, управляемые Google.
Ваш сервер приложений или среда доверенного сервера отправляет запросы сообщений на серверную часть FCM, которая затем направляет сообщения в клиентские приложения, работающие на устройствах пользователей.
Требования к среде доверенного сервера
Ваша среда сервера приложений должна соответствовать следующим критериям:
- Возможность отправлять правильно отформатированные запросы сообщений на серверную часть FCM.
- Способен обрабатывать запросы и повторно отправлять их, используя экспоненциальную отсрочку.
- Возможность безопасного хранения учетных данных авторизации сервера и токенов регистрации клиентов.
- Для протокола XMPP (если он используется) сервер должен иметь возможность генерировать идентификаторы сообщений, чтобы однозначно идентифицировать каждое отправляемое им сообщение (базовая часть FCM HTTP генерирует идентификаторы сообщений и возвращает их в ответе). Идентификаторы сообщений XMPP должны быть уникальными для каждого идентификатора отправителя.
Выбор варианта сервера
Вам нужно будет выбрать способ взаимодействия с серверами FCM: либо с помощью Firebase Admin SDK , либо с использованием необработанных протоколов. Из-за поддержки популярных языков программирования и удобных методов аутентификации и авторизации рекомендуется использовать Firebase Admin SDK.
Варианты взаимодействия с серверами FCM включают следующее:
- Firebase Admin SDK с поддержкой Node , Java , Python , C# и Go .
- API FCM HTTP v1 , который является самым современным из вариантов протокола, с более безопасной авторизацией и гибкими возможностями межплатформенного обмена сообщениями (SDK Firebase Admin основан на этом протоколе и предоставляет все присущие ему преимущества). Поскольку новые функции обычно добавляются только в HTTP v1 API, мы рекомендуем использовать этот API в большинстве случаев.
- Устаревший HTTP- протокол. Новым проектам настоятельно рекомендуется использовать HTTP API FCM v1 вместо устаревшего протокола.
- Устаревший протокол сервера XMPP . Новым проектам настоятельно рекомендуется использовать HTTP API FCM v1 вместо устаревшего протокола.
Firebase Admin SDK для FCM
API-интерфейс Admin FCM обрабатывает аутентификацию с помощью серверной части и облегчает отправку сообщений и управление подписками на темы. С Firebase Admin SDK вы можете:
- Отправка сообщений на отдельные устройства
- Отправляйте сообщения в темы и операторы условий, соответствующие одной или нескольким темам.
- Подписка устройств на темы и отписка от них
- Создавайте полезные нагрузки сообщений, адаптированные к различным целевым платформам.
Пакет SDK Admin Node.js предоставляет методы для отправки сообщений группам устройств.
Чтобы настроить Firebase Admin SDK, см. Добавление Firebase Admin SDK на ваш сервер . Если у вас уже есть проект Firebase, начните с добавления SDK . Кроме того, обязательно включите Cloud Messagin API на странице настроек Cloud Messaging для вашего проекта. Затем, после установки Firebase Admin SDK, вы можете приступить к написанию логики для создания запросов на отправку .
Протоколы сервера FCM
В настоящее время FCM предоставляет следующие необработанные серверные протоколы:
- API FCM HTTP v1
- Устаревший HTTP-протокол
- Устаревший протокол XMPP
Ваш сервер приложений может использовать эти протоколы по отдельности или вместе. Поскольку это самый современный и гибкий способ отправки сообщений на несколько платформ, по возможности рекомендуется использовать FCM HTTP v1 API. Если ваши требования включают передачу сообщений от устройств к серверу, вам необходимо реализовать протокол XMPP.
Обмен сообщениями XMPP отличается от обмена сообщениями HTTP следующими способами:
- Восходящие/нисходящие сообщения
- HTTP: только нисходящий поток, от облака к устройству.
- XMPP: восходящий и нисходящий (от устройства к облаку, от облака к устройству).
- Обмен сообщениями (синхронный или асинхронный)
- HTTP: синхронный. Серверы приложений отправляют сообщения в виде запросов HTTP POST и ждут ответа. Этот механизм является синхронным и не позволяет отправителю отправить другое сообщение до тех пор, пока не будет получен ответ.
- XMPP: асинхронный. Серверы приложений отправляют/получают сообщения на/со всех своих устройств на полной скорости линии через постоянные соединения XMPP. Сервер соединений XMPP отправляет подтверждения или уведомления об ошибках (в виде специальных сообщений XMPP ACK и NACK, закодированных в формате JSON) асинхронно.
- JSON
- HTTP: сообщения JSON отправляются как HTTP POST.
- XMPP: сообщения JSON, инкапсулированные в сообщения XMPP.
- Простой текст
- HTTP: обычные текстовые сообщения, отправленные как HTTP POST.
- XMPP: не поддерживается.
- Многоадресная рассылка в нисходящем направлении на несколько регистрационных токенов.
- HTTP: поддерживается в формате сообщений JSON.
- XMPP: не поддерживается.
Реализация протокола HTTP-сервера
Чтобы отправить сообщение, сервер приложений отправляет запрос POST с заголовком HTTP и телом HTTP, состоящим из пар ключ-значение JSON. Дополнительные сведения о параметрах заголовка и тела см. в разделе Сборка запросов на отправку сервера приложений.
Реализация протокола сервера XMPP
Полезная нагрузка JSON для сообщений FCM аналогична протоколу HTTP со следующими исключениями:
- Нет поддержки нескольких получателей.
- FCM добавляет обязательное поле
message_id
. Этот идентификатор однозначно идентифицирует сообщение в соединении XMPP. ACK или NACK от FCM используетmessage_id
для идентификации сообщения, отправленного с серверов приложений в FCM. Поэтому важно, чтобы этотmessage_id
был не только уникальным (для идентификатора отправителя ), но и всегда присутствовал. - XMPP использует ключ сервера для авторизации постоянного подключения к FCM. Дополнительные сведения см. в разделе Авторизация запросов на отправку .
В дополнение к обычным сообщениям FCM отправляются управляющие сообщения, указанные в поле message_type
в объекте JSON. Значение может быть либо «ack», либо «nack», либо «control» (см. форматы ниже). Любое сообщение FCM с неизвестным message_type
может быть проигнорировано вашим сервером.
Для каждого сообщения устройства, которое ваш сервер приложений получает от FCM, ему необходимо отправить сообщение ACK. Ему никогда не нужно посылать сообщение NACK. Если вы не отправляете ACK для сообщения, FCM повторно отправляет его при следующем установлении нового соединения XMPP, если только сообщение не истечет раньше.
FCM также отправляет ACK или NACK для каждого сообщения от сервера к устройству. Если вы не получили ни того, ни другого, это означает, что TCP-соединение было закрыто в середине операции, и вашему серверу необходимо повторно отправить сообщения. Подробнее см. в разделе Управление потоком .
См. Справочник по протоколу для получения списка всех параметров сообщения.
Формат запроса
Сообщение с полезной нагрузкой — уведомление
Вот строфа XMPP для сообщения уведомления:
<message id=""> <gcm xmlns="google:mobile:data"> { "to":"REGISTRATION_ID", // "to" replaces "registration_ids" "notification": { "title": "Portugal vs. Denmark”, "body”: "5 to 1” }, "time_to_live":"600" } </gcm> </message>
Сообщение с полезной нагрузкой — сообщение данных
Вот строфа XMPP, содержащая сообщение JSON от сервера приложений к FCM:
<message id=""> <gcm xmlns="google:mobile:data"> { "to":"REGISTRATION_ID", // "to" replaces "registration_ids" "message_id":"m-1366082849205" // new required field "data": { "hello":"world", } "time_to_live":"600", } </gcm> </message>
Формат ответа
Ответ FCM может иметь три возможные формы. Первое — это обычное сообщение «подтверждение». Но когда ответ содержит ошибку, сообщение может принимать две разные формы, описанные ниже.
ACK-сообщение
Вот строфа XMPP, содержащая сообщение ACK/NACK от FCM к серверу приложений:
<message id=""> <gcm xmlns="google:mobile:data"> { "from":"REGID", "message_id":"m-1366082849205" "message_type":"ack" } </gcm> </message>
NACK-сообщение
Ошибка NACK — это обычное сообщение XMPP, в котором сообщение о состоянии message_type
имеет значение «nack». Сообщение NACK содержит:
- Код ошибки NACK.
- Описание ошибки NACK.
Ниже приведены некоторые примеры.
Плохая регистрация:
<message> <gcm xmlns="google:mobile:data"> { "message_type":"nack", "message_id":"msgId1", "from":"SomeInvalidRegistrationToken", "error":"BAD_REGISTRATION", "error_description":"Invalid token on 'to' field: SomeInvalidRegistrationId" } </gcm> </message>
Неверный JSON:
<message> <gcm xmlns="google:mobile:data"> { "message_type":"nack", "message_id":"msgId1", "from":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...", "error":"INVALID_JSON", "error_description":"InvalidJson: JSON_TYPE_ERROR : Field \"time_to_live\" must be a JSON java.lang.Number: abc" } </gcm> </message>
Скорость сообщений устройства превышена:
<message id="..."> <gcm xmlns="google:mobile:data"> { "message_type":"nack", "message_id":"msgId1", "from":"REGID", "error":"DEVICE_MESSAGE_RATE_EXCEEDED", "error_description":"Downstream message rate exceeded for this registration id" } </gcm> </message>
Полный список кодов ошибок NACK см . в справочнике по серверу . Если не указано иное, сообщение NACK не следует повторять. Неожиданные коды ошибок NACK следует обрабатывать так же, как INTERNAL_SERVER_ERROR
.
Ошибка строфы
Вы также можете получить ошибку строфы в некоторых случаях. Ошибка строфы содержит:
- Код ошибки строфы.
- Описание ошибки строфы (свободный текст).
Например:
<message id="3" type="error" to="123456789@fcm.googleapis.com/ABC"> <gcm xmlns="google:mobile:data"> {"random": "text"} </gcm> <error code="400" type="modify"> <bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/> <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"> InvalidJson: JSON_PARSING_ERROR : Missing Required Field: message_id\n </text> </error> </message>
Сообщения управления
Периодически FCM необходимо закрывать соединение для выполнения балансировки нагрузки. Прежде чем закрыть соединение, FCM отправляет сообщение CONNECTION_DRAINING
, чтобы указать, что соединение сбрасывается и скоро будет закрыто. «Опорожнение» относится к отключению потока сообщений, поступающих в соединение, но разрешению продолжения того, что уже находится в конвейере. Когда вы получаете сообщение CONNECTION_DRAINING
, вы должны немедленно начать отправку сообщений на другое соединение FCM, при необходимости открывая новое соединение. Однако вы должны держать исходное соединение открытым и продолжать получать сообщения, которые могут поступать через соединение (и подтверждать их) — FCM обрабатывает инициирование закрытия соединения, когда оно готово.
Сообщение CONNECTION_DRAINING
выглядит следующим образом:
<message> <data:gcm xmlns:data="google:mobile:data"> { "message_type":"control" "control_type":"CONNECTION_DRAINING" } </data:gcm> </message>
CONNECTION_DRAINING
в настоящее время является единственным поддерживаемым control_type
.
Управление потоком
Каждое сообщение, отправленное в FCM, получает ответ ACK или NACK. Сообщения, не получившие ни одного из этих ответов, считаются ожидающими. Если количество ожидающих сообщений достигает 100, сервер приложений должен прекратить отправку новых сообщений и подождать, пока FCM подтвердит некоторые из существующих ожидающих сообщений, как показано на рисунке 1:
Рисунок 1. Поток сообщений/подтверждений.
И наоборот, чтобы избежать перегрузки сервера приложений, FCM прекращает отправку, если слишком много неподтвержденных сообщений. Таким образом, сервер приложений должен как можно скорее «подтвердить» восходящие сообщения, полученные от клиентского приложения через FCM, чтобы поддерживать постоянный поток входящих сообщений. Вышеупомянутый лимит ожидающих сообщений не применяется к этим ACK. Даже если количество ожидающих сообщений достигает 100, сервер приложений должен продолжать отправлять ACK для сообщений, полученных от FCM, чтобы избежать блокировки доставки новых восходящих сообщений.
ACK действительны только в контексте одного соединения. Если соединение закрывается до того, как сообщение может быть подтверждено ACK, сервер приложений должен дождаться, пока FCM повторно отправит восходящее сообщение, прежде чем снова подтвердить его. Точно так же все ожидающие сообщения, для которых ACK/NACK не был получен от FCM до того, как соединение было закрыто, должны быть отправлены снова.