Firebase 云消息传递的服务器端包含两个组件:
- 由 Google 提供的 FCM 后端。
- 您的应用服务器或运行服务器逻辑的其他可信服务器环境,例如 Cloud Functions for Firebase 或由 Google 管理的其他云环境。
应用服务器或受信任的服务器环境向 FCM 后端发送消息请求,然后 FCM 后端再将消息发送到用户设备上运行的客户端应用。
受信任的服务器环境的要求
您的应用服务器环境必须符合以下条件:
- 能够向 FCM 后端发送格式正确的消息请求。
- 能够使用指数退避算法处理请求和重新发送请求。
- 能够安全地存储服务器授权凭据和客户端注册令牌。
- 对于 XMPP 协议(如果使用),服务器必须能够生成消息 ID 来唯一标识它发送的每条消息(FCM HTTP 后端会生成消息 ID 并在响应时返回这些 ID)。XMPP 消息 ID 对于每个发送者 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 协议。
- XMPP 服务器协议。请注意,如果您想从客户端应用使用上游消息传递功能,则必须使用 XMPP。
适用于 FCM 的 Firebase Admin SDK
Admin FCM API 可处理后端身份验证工作,同时便于发送消息和管理主题订阅。使用 Firebase Admin SDK,您可以执行以下操作:
- 向个别设备发送消息
- 向主题和与一个或多个主题匹配的条件语句发送消息。
- 为设备订阅和退订主题
- 针对不同目标平台构建量身定制的消息负载。
Admin Node.js SDK 提供了用于向设备组发送消息的方法。
如需设置 Firebase Admin SDK,请参阅将 Firebase Admin SDK 添加到您的服务器。如果您已有 Firebase 项目,请先使用添加 SDK 。然后,安装 Firebase Admin SDK 后,您就可以开始将逻辑写入构建发送请求。
FCM 服务器协议
目前 FCM 提供以下原始服务器协议:
- FCM HTTP v1 API
- 旧版 HTTP 协议
- 旧版 XMPP 协议
您的应用服务器可以分开使用或同时使用这些协议。因为在向多个平台发送消息方面 FCM HTTP v1 API 是最新、最灵活的协议,因此推荐尽可能使用此协议。如果您需要从设备到服务器的上行消息传递功能,则需实现 XMPP 协议。
XMPP 消息传递与 HTTP 消息传递具有以下差异:
- 上行/下行消息
- HTTP:仅下行,即云到设备。
- XMPP:上行和下行(即设备到云、云到设备)。
- 消息传递(同步或异步)
- HTTP:同步。应用服务器以 HTTP POST 请求的形式发送消息,并等待响应。此机制是同步的,且发送者无法在收到响应前发送其他消息。
- XMPP:异步。应用服务器通过持续型 XMPP 连接,以全线速向/从所有设备发送/接收消息。 XMPP 连接服务器异步发送确认或失败通知(以 ACK 和 NACK JSON 编码的特殊 XMPP 消息形式)。
- JSON
- HTTP:JSON 消息以 HTTP POST 的形式发送。
- XMPP:JSON 消息封装在 XMPP 消息中。
- 纯文本
- HTTP:纯文本消息以 HTTP POST 的形式发送。
- XMPP:不支持。
- 向多个注册令牌发送多播下行消息。
- HTTP:支持 JSON 格式的消息。
- XMPP:不支持。
实现 HTTP 服务器协议
如需发送消息,应用服务器需发出包含 HTTP 标头和 HTTP 正文(由 JSON 键值对组成)的 POST 请求。 如需详细了解标头和正文选项,请参阅构建应用服务器发送请求
实现 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>
包含有效载荷的消息 - 数据消息
以下是一个含有从应用服务器发送至 FCM 的 JSON 消息的 XMPP 节:
<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”消息。但是,如果响应中包含错误,消息可能有 2 种不同形式,如下所述。
ACK 消息
以下是一个包含从 FCM 发送至应用服务器的 ACK/NACK 消息的 XMPP 节:
<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":"SomeInvalidRegistrationId", "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 连接发送消息,还可根据需要开启一个新的连接。但是,您应该让原来的连接保持开启状态,并继续接收可能来自该连接的消息(并对其进行确认 ACK)。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. 消息/确认 (ack) 流。
反之而言,为了避免应用服务器过载,如果有太多未确认的消息,FCM 也将停止发送上行消息。因此,应用服务器应尽快“ACK”(确认)通过 FCM 收到的来自客户端应用的上行消息,以便尽快地维持持续不断的传入消息流。上述待处理消息限制不适用于这类 ACK。即使待处理消息数量达到 100 条,应用服务器也应继续为从 FCM 收到的消息发送 ACK,以避免阻塞新的上行消息的传递。
ACK 仅在同一个连接的上下文环境中有效。如果连接在消息确认 (ACK) 前关闭了,应用服务器应等待 FCM 重新发送该上行消息,然后再次对其进行确认。同样地,所有未能在连接关闭之前从 FCM 收到 ACK/NACK 的待处理消息都应重新发送。