您的服务器环境和 FCM
Firebase Cloud Messaging 的服务器端由两个组件组成:
- Google 提供的FCM 后端。
- 您的应用服务器或您的服务器逻辑运行的其他可信服务器环境,例如Cloud Functions for Firebase或其他由 Google 管理的云环境。
您的应用程序服务器或受信任的服务器环境将消息请求发送到 FCM 后端,然后将消息路由到用户设备上运行的客户端应用程序。
可信服务器环境要求
您的应用服务器环境必须满足以下条件:
- 能够向 FCM 后端发送格式正确的消息请求。
- 能够处理请求并使用指数退避重新发送它们。
- 能够安全地存储服务器授权凭证和客户端注册令牌。
- 对于 XMPP 协议(如果使用),服务器必须能够生成消息 ID 以唯一标识它发送的每条消息(FCM HTTP 后端生成消息 ID 并在响应中返回它们)。每个发件人 ID 的 XMPP 消息 ID 应该是唯一的。
选择服务器选项
您需要决定与 FCM 服务器交互的方式:使用Firebase Admin SDK或原始协议。由于它支持各种流行的编程语言,并且处理身份验证和授权的方法很方便,因此推荐使用 Firebase Admin SDK。
与 FCM 服务器交互的选项包括:
- Firebase Admin SDK,支持Node 、 Java 、 Python 、 C#和Go 。
- FCM HTTP v1 API ,这是最新的协议选项,具有更安全的授权和灵活的跨平台消息传递功能(Firebase Admin SDK 基于此协议并提供其所有固有优势)。由于新功能通常仅添加到 HTTP v1 API,因此我们建议在大多数用例中使用此 API。
- 旧版 HTTP协议。强烈建议新项目采用 FCM v1 HTTP API 而不是旧协议。
- 旧版 XMPP服务器协议。强烈建议新项目采用 FCM v1 HTTP API 而不是旧协议。
适用于 FCM 的 Firebase 管理 SDK
Admin FCM API 处理与后端的身份验证,并促进发送消息和管理主题订阅。借助 Firebase Admin SDK,您可以:
- 向各个设备发送消息
- 向匹配一个或多个主题的主题和条件语句发送消息。
- 订阅和取消订阅设备主题
- 构建适合不同目标平台的消息负载
Admin Node.js SDK 提供了向设备组发送消息的方法。
要设置 Firebase Admin SDK,请参阅将 Firebase Admin SDK 添加到您的服务器。如果您已有 Firebase 项目,请从添加 SDK开始。此外,请确保在项目的云消息传递设置页面中启用云消息传递 API。然后,一旦安装了 Firebase Admin SDK,您就可以开始编写逻辑来构建发送请求。
FCM 服务器协议
目前 FCM 提供这些原始服务器协议:
您的应用程序服务器可以单独或串联使用这些协议。由于它是向多个平台发送消息的最新和最灵活的方法,因此在可行的情况下建议使用 FCM HTTP v1 API。如果您的要求包括从设备到服务器的上游消息传递,则需要实施 XMPP 协议。
XMPP 消息传递在以下方面不同于 HTTP 消息传递:
- 上游/下游消息
- HTTP:仅下游,云到设备。
- XMPP:上游和下游(设备到云,云到设备)。
- 消息传递(同步或异步)
- HTTP:同步。应用程序服务器将消息作为 HTTP POST 请求发送并等待响应。此机制是同步的,并阻止发送方发送另一条消息,直到收到响应。
- XMPP:异步。应用程序服务器通过持久的 XMPP 连接以全线速度向/从其所有设备发送/接收消息。 XMPP 连接服务器异步发送确认或失败通知(以特殊的 ACK 和 NACK JSON 编码的 XMPP 消息的形式)。
- JSON
- HTTP:作为 HTTP POST 发送的 JSON 消息。
- XMPP:封装在 XMPP 消息中的 JSON 消息。
- 纯文本
- HTTP:作为 HTTP POST 发送的纯文本消息。
- XMPP:不支持。
- 多播下游发送到多个注册令牌。
- HTTP:支持 JSON 消息格式。
- XMPP:不支持。
实现 HTTP 服务器协议
要发送消息,应用程序服务器会发出一个 POST 请求,其中包含 HTTP 标头和由 JSON 键值对组成的 HTTP 正文。有关标头和正文选项的详细信息,请参阅构建应用服务器发送请求
实现 XMPP 服务器协议
FCM 消息的 JSON 负载类似于 HTTP 协议,但有以下例外:
- 不支持多个收件人。
- FCM 添加了字段
message_id
,这是必需的。此 ID 唯一标识 XMPP 连接中的消息。来自 FCM 的 ACK 或 NACK 使用message_id
来标识从应用服务器发送到 FCM 的消息。因此,重要的是这个message_id
不仅是唯一的(每个发件人 ID ),而且始终存在。 - XMPP 使用服务器密钥授权与 FCM 的持久连接。有关详细信息,请参阅授权发送请求。
除了常规的 FCM 消息外,还会发送控制消息,由 JSON 对象中的message_type
字段指示。该值可以是“ack”或“nack”,或“control”(参见下面的格式)。您的服务器可以忽略任何具有未知message_type
的 FCM 消息。
对于您的应用服务器从 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 节,其中包含从应用服务器到 FCM 的 JSON 消息:
<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 响应可以有三种可能的形式。第一个是常规的“确认”消息。但是当响应包含错误时,消息可以采用 2 种不同的形式,如下所述。
确认消息
这是一个 XMPP 节,其中包含从 FCM 到应用服务器的 ACK/NACK 消息:
<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 错误代码的完整列表,请参阅服务器参考。除非另有说明,否则不应重试 NACKed 消息。意外的 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
消息以指示连接正在被耗尽并将很快关闭。 “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,应用服务器也应继续为从 FCM 收到的消息发送 ACK,以避免阻止新上游消息的传递。
ACK 仅在一个连接的上下文中有效。如果连接在消息可以被确认之前关闭,应用服务器应该等待 FCM 重新发送上游消息,然后再再次确认它。同样,在关闭连接之前未从 FCM 收到 ACK/NACK 的所有未决消息都应再次发送。