Tu entorno de servidor y FCM
Los servidores de Firebase Cloud Messaging tienen dos componentes:
- El backend de FCM proporcionado por Google
- Tu servidor de apps, o bien otro entorno de servidor de confianza, en el que se ejecuta la lógica del servidor, como Cloud Functions para Firebase o entornos de nube administrados por Google
El servidor de apps o el entorno de servidor de confianza envía solicitudes de mensajes al backend de FCM, que luego envía mensajes a las apps cliente que se ejecutan en los dispositivos de los usuarios.
Requisitos del entorno de servidor de confianza
El entorno del servidor de apps debe cumplir con los siguientes criterios:
- Poder enviar solicitudes de mensajes con el formato correcto al backend de FCM
- Poder administrar solicitudes y reenviarlas con una retirada exponencial
- Poder almacenar las credenciales de autorización del servidor y los tokens de registro de cliente de forma segura
- Si se usa el protocolo XMPP, el servidor debe generar ID de mensajes a fin de identificar exclusivamente cada mensaje que envía (el backend de HTTP de FCM genera ID de mensajes y los muestra en la respuesta); los ID de mensajes XMPP deben ser únicos por ID de remitente
Elige una opción de servidor
Deberás decidir de qué manera comunicarte con los servidores de FCM: a través del SDK de Firebase Admin o los protocolos sin procesar. El SDK de Firebase Admin es el método recomendado, ya que es compatible con lenguajes de programación populares y cuenta con métodos útiles para controlar la autenticación y la autorización.
Para comunicarte con los servidores de FCM, puedes usar las siguientes opciones:
- El SDK de Firebase Admin, que es compatible con Node.js, Java, Python, C# y Go
- La API de FCM HTTP v1, que es la opción de protocolo más actualizada y cuenta con una autorización más segura y funciones flexibles de mensajería multiplataforma (el SDK de Firebase Admin se basa en este protocolo y proporciona todas sus ventajas propias) Debido a que, por lo general, las funciones nuevas se agregan solo a la API de HTTP v1, recomendamos usar esta API para la mayoría de los casos de uso.
- El protocolo HTTP heredado. Se recomienda que los proyectos nuevos adopten la API de HTTP versión 1 de FCM en lugar del protocolo heredado.
- El protocolo del servidor XMPP heredado Se recomienda que los proyectos nuevos adopten la API de HTTP versión 1 de FCM en lugar del protocolo heredado.
SDK de Firebase Admin para FCM
La API de Admin de FCM se encarga de la autenticación con el backend y facilita el envío de mensajes y la administración de suscripciones a temas. Con el SDK de Firebase Admin, puedes realizar las siguientes operaciones:
- Enviar mensajes a dispositivos individuales
- Enviar mensajes a temas y declaraciones de estado que coincidan con uno o más temas
- Suscribir dispositivos a temas y anular suscripciones a ellos
- Generar cargas útiles de mensaje adaptadas a distintas plataformas de destino
El SDK de Admin de Node.js proporciona métodos para enviar mensajes a grupos de dispositivos.
Si quieres configurar el SDK de Firebase Admin, consulta Agrega el SDK de Firebase Admin a tu servidor. Si ya tienes un proyecto de Firebase, primero consulta Agrega el SDK. Además, asegúrate de habilitar la API de Cloud Messaging en la página de configuración de Cloud Messaging del proyecto. Una vez que instales el SDK de Firebase Admin, podrás comenzar a escribir la lógica para crear solicitudes de envío.
Protocolos de servidor FCM
Actualmente, FCM proporciona los siguientes protocolos de servidor sin procesar:
- API de FCM HTTP v1
- Protocolo HTTP heredado
- Protocolo XMPP heredado
Tu servidor de apps puede usar estos protocolos de manera independiente o en conjunto. Te recomendamos usar la API de FCM HTTP v1 siempre que sea posible, ya que es la más actualizada y flexible para enviar mensajes a diversas plataformas. Si tus requisitos incluyen la mensajería ascendente desde los dispositivos al servidor, deberás implementar el protocolo XMPP.
La mensajería XMPP difiere de la mensajería HTTP de las siguientes formas:
- Mensajes ascendentes/descendentes
- HTTP: Solo descendentes, de la nube al dispositivo
- XMPP: Ascendentes y descendentes (del dispositivo a la nube y de la nube al dispositivo)
- Mensajería (síncrona o asíncrona)
- HTTP: Síncrono. Los servidores de apps envían mensajes como solicitudes HTTP POST y esperan una respuesta. Este mecanismo es síncrono y bloquea al emisor para que no pueda enviar otro mensaje hasta que se reciba la respuesta.
- XMPP: Asíncrono. Los servidores de apps envían y reciben mensajes hacia y desde todos los dispositivos a velocidad máxima a través de conexiones XMPP persistentes. El servidor de conexiones XMPP envía notificaciones de confirmación o de error (en la forma de mensajes XMPP ACK y NACK especiales codificados en JSON) de forma asíncrona.
- JSON
- HTTP: Mensajes JSON enviados como HTTP POST
- XMPP: Mensajes JSON encapsulados en mensajes XMPP
- Texto sin formato
- HTTP: Mensajes de texto sin formato enviados como HTTP POST
- XMPP: No compatible
- Mensajes multidifusión descendentes enviados a diversos tokens de registro
- HTTP: Compatible con el formato de mensajes JSON
- XMPP: No compatible
Implementación del protocolo de servidor HTTP
Para enviar un mensaje, el servidor de apps envía una solicitud POST con un encabezado HTTP y un cuerpo HTTP compuesto por pares clave-valor JSON. Para ver detalles sobre las opciones de encabezado y cuerpo, consulta Compila solicitudes de envío del servidor de apps.
Implementación del protocolo del servidor XMPP
La carga útil JSON para mensajes FCM es similar al protocolo HTTP, con las siguientes excepciones:
- No admite múltiples receptores.
- FCM agrega el campo
message_id
, que es obligatorio. Este ID identifica exclusivamente el mensaje en una conexión XMPP. El ACK o NACK de FCM usa elmessage_id
para identificar un mensaje enviado desde los servidores de apps a FCM. Por lo tanto, es importante que estemessage_id
no solo sea único (por ID de remitente), sino que siempre esté presente. - XMPP usa la clave de servidor para autorizar una conexión continua a FCM. Consulta Autoriza solicitudes de envío para obtener más información.
Además de los mensajes habituales de FCM, se envían mensajes de control indicados por el campo message_type
en el objeto JSON. El valor puede ser “ack” o “nack”, o “control” (consulta los formatos a continuación). Tu servidor puede ignorar cualquier mensaje de FCM con un valor desconocido de message_type
.
Por cada mensaje de dispositivo que tu servidor de apps recibe de FCM, el servidor debe enviar un mensaje ACK. Nunca es necesario que envíe un mensaje NACK. Si no envías un ACK para un mensaje, FCM lo reenvía la próxima vez que se establece una nueva conexión XMPP, a menos que el mensaje caduque antes.
FCM también envía un ACK o NACK para cada mensaje de servidor a dispositivo. Si no recibes ninguno, significa que la conexión TCP se cerró durante la operación y tu servidor debe reenviar los mensajes. Consulta Control de flujo para obtener información detallada.
Consulta la Referencia del protocolo para ver una lista de todos los parámetros de mensajes.
Formato de la solicitud
Mensaje con carga útil: Mensaje de notificación
La siguiente es una estrofa XMPP para un mensaje de notificación:
<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>
Mensaje con carga útil: Mensaje de datos
La siguiente es una estrofa XMPP que contiene el mensaje JSON de un servidor de apps a 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>
Formato de la respuesta
Una respuesta de FCM puede tener tres formatos posibles. El primero es un mensaje "ack" normal. Sin embargo, cuando la respuesta contiene un error, el mensaje puede asumir dos formatos diferentes, que se describen a continuación.
Mensaje ACK
La siguiente es una estrofa XMPP que contiene el mensaje ACK/NACK de FCM al servidor de apps:
<message id=""> <gcm xmlns="google:mobile:data"> { "from":"REGID", "message_id":"m-1366082849205" "message_type":"ack" } </gcm> </message>
Mensaje NACK
Un error NACK es un mensaje XMPP normal en el que el mensaje de estado message_type
es “nack”. Un mensaje NACK contiene lo siguiente:
- Un código de error NACK
- Una descripción de error NACK
A continuación, hay algunos ejemplos.
Registro incorrecto:
<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 no válido:
<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>
Tasa de mensajes de dispositivos excedida:
<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>
Consulta la Referencia de servidores para obtener una lista completa de los códigos de error NACK. A menos que se indique lo contrario, no se debe reintentar el envío de un mensaje con NACK. Los códigos de error NACK inesperados se deben tratar de la misma forma que INTERNAL_SERVER_ERROR
.
Error de estrofa
También puedes obtener un error de estrofa en ciertos casos. Un error de estrofa contiene lo siguiente:
- El código de error de estrofa
- La descripción de error de estrofa (texto libre)
Por ejemplo:
<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>
Mensajes de control
Periódicamente, FCM debe cerrar una conexión para realizar el balanceo de cargas. Antes de cerrar la conexión, FCM envía un mensaje de CONNECTION_DRAINING
para indicar que la conexión se está drenando y se cerrará pronto. “Drenar” se refiere a cortar el flujo de mensajes que llegan a una conexión, pero permitir que continúen los que ya están dentro de la canalización. Cuando recibes un mensaje de CONNECTION_DRAINING
, debes comenzar a enviar mensajes de inmediato a otra conexión de FCM y, si es necesario, abrir una nueva. Sin embargo, debes mantener la conexión original abierta y continuar recibiendo mensajes que puedan venir a través de la conexión (y confirmarlos con ACK). FCM se encarga de iniciar el cierre de una conexión cuando está lista.
El mensaje de CONNECTION_DRAINING
luce de la siguiente manera:
<message> <data:gcm xmlns:data="google:mobile:data"> { "message_type":"control" "control_type":"CONNECTION_DRAINING" } </data:gcm> </message>
CONNECTION_DRAINING
es el único control_type
compatible actualmente.
Control de flujo
Cada mensaje enviado a FCM recibe una respuesta ACK o NACK. Los mensajes que no recibieron una de estas respuestas se consideran pendientes. Si el conteo de mensajes pendientes llega a 100, el servidor de apps debe dejar de enviar nuevos mensajes y esperar a que FCM reconozca algunos de los mensajes pendientes existentes, como se muestra en la figura 1:
De modo inverso, para evitar la sobrecarga del servidor de apps, FCM deja de enviar mensajes si hay demasiados mensajes sin confirmar. Por lo tanto, el servidor de apps debe confirmar con ACK los mensajes ascendentes que recibe de la aplicación cliente a través de FCM apenas pueda, para mantener un flujo constante de mensajes entrantes. El límite de mensajes pendientes mencionado previamente no corresponde a estas confirmaciones ACK. Incluso si el conteo de mensajes pendientes llega a 100, el servidor de apps debe continuar enviando confirmaciones para los mensajes recibidos de FCM a fin de evitar que se bloquee la entrega de mensajes ascendentes nuevos.
Las confirmaciones ACK son solo válidas dentro del contexto de una conexión. Si la conexión se cierra antes de que un mensaje se confirme con ACK, el servidor de apps debe esperar a que FCM reenvíe el mensaje ascendente antes de volver a intentar la confirmación. De manera similar, se deben volver a enviar todos los mensajes pendientes para los que no se recibió un ACK/NACK de FCM antes de que se cerrara la conexión.