Firebase 云消息传递服务器简介

Firebase 云消息传递的服务器端包含两个组件:

应用服务器或受信任的服务器环境向 FCM 服务器发送消息请求,然后 FCM 服务器再将消息发送到用户设备上运行的客户端应用。

如需详细了解如何实现客户端,请参阅适合您的平台(iOSAndroid网页)的客户端指南。

受信任的服务器环境的作用

为了能编写使用 Firebase 云消息传递的客户端应用,您必须拥有一个满足以下标准的服务器环境:

  • 能够与您的客户端通信。
  • 能够向 FCM 服务器发送格式正确的消息请求。
  • 能够使用指数退避算法处理请求和重新发送请求。
  • 能够安全存储服务器密钥和客户端注册令牌。请注意,切勿在任何客户端代码中包含服务器密钥。
  • 对于 XMPP,服务器必须能生成消息 ID 来唯一标识它发送的每条消息(FCM HTTP 连接服务器会生成消息 ID 并在响应时返回这些 ID)。XMPP 消息 ID 对于每个发送者 ID 而言都应是唯一的。

您需要决定与 FCM 服务器进行交互的方式:使用 Admin SDK 或使用原始协议。在原始协议选项中,FCM HTTP v1 API 是最新的,且具有更安全的授权功能和灵活的跨平台消息传递功能。您也可以使用旧版的 HTTPXMPP 服务器协议。请注意,如果您想在客户端应用中使用上行消息传递功能,则必须使用 XMPP。如需这方面的更多介绍,请参阅 FCM 服务器协议

FCM 服务器协议

目前 FCM 提供以下原始服务器协议:

您的应用服务器可以分开使用或同时使用这些协议。因为在向多个平台发送消息方面 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 Stanza:

<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",
      "delivery_receipt_requested": true/false
  }
  </gcm>
</message>

响应格式

FCM 响应有三种可能的形式。第一种是常规的“ack”消息。但是,如果响应中包含错误,消息可能有两种不同形式,如下所述。

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@gcm.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

接收送达回执

对于 Android 和 Chrome 客户端应用,当设备确认已收到由 FCM 发送的消息后,您可以获得送达回执(从 FCM 发送至您的应用服务器)。

要启用此功能,从您的应用服务器发送至 FCM 的消息必须包含 delivery_receipt_requested 字段。如果此字段设置为 true,则当设备确认已收到某条特定消息时,FCM 将发送送达回执。

以下是一个含有 JSON 消息的 XMPP 节,其中 "delivery_receipt_requested" 设置为 true

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "to":"REGISTRATION_ID",
      "message_id":"m-1366082849205"
      "data":
      {
          "hello":"world",
      }
      "time_to_live":"600",
      "delivery_receipt_requested": true
  }
  </gcm>
</message>

以下是 FCM 发送的送达回执示例,用于向您的应用服务器报告设备已收到来自 FCM 的消息:

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "category":"com.example.yourapp", // to know which app sent it
      "data":
      {
         “message_status":"MESSAGE_SENT_TO_DEVICE",
         “original_message_id”:”m-1366082849205”
         “device_registration_id”: “REGISTRATION_ID”
      },
      "message_id":"dr2:m-1366082849205",
      "message_type":"receipt",
      "from":"gcm.googleapis.com"
  }
  </gcm>
</message>

注意事项:

  • "message_type" 设置为 "receipt"
  • "message_status" 设置为 "MESSAGE_SENT_TO_DEVICE",表示设备已收到消息。此时请注意,"message_status" 不是一个字段,而是数据有效负载的一部分。
  • 回执消息 ID 包含原始消息 ID,但带有一个前缀 dr2:。您的应用服务器必须使用相同的连接来发回带有此 ID 的 ACK,在本示例中为 dr2:m-1366082849205
  • 原始消息 ID、设备注册令牌以及状态均包含在 "data" 字段中。
  • 如果 FCM 与设备之间的连接不稳定,Firebase 云消息传递可能会发送多个重复的送达回执。您可以放心地忽略这些重复回执。

流控制

发送至 FCM 的每一条消息都会收到 ACK 或 NACK 响应。未收到其中任何一种响应的消息被视为待处理。如果待处理的消息数量达到 100 条,应用服务器应当停止发送新的消息,等待 FCM 对某些现有的待处理消息进行确认,如图 1 所示:

图 1. 消息/确认 (ack) 流。

反之而言,为了避免应用服务器过载,如果有太多未确认的消息,FCM 也将停止发送上行消息。因此,应用服务器应尽快“ACK”(确认)通过 FCM 收到的来自客户端应用的上行消息,以便尽快地维持持续不断的传入消息流。上述待处理消息限制不适用于这类 ACK。即使待处理消息数量达到 100 条,应用服务器也应继续为从 FCM 收到的消息发送 ACK,以避免阻塞新的上行消息的传递。

ACK 仅在同一个连接的上下文环境中有效。如果连接在消息确认 (ACK) 前关闭了,应用服务器应等待 FCM 重新发送该上行消息,然后再次对其进行确认。同样地,所有未能在连接关闭之前从 FCM 收到 ACK/NACK 的待处理消息都应重新发送。

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面