获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情
使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

您的服务器环境和 FCM

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

  • 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,支持NodeJavaPythonC#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 所示:

FCM与app server之间的控制流程详图

图 1.消息/确认流。

相反,为了避免应用服务器过载,如果未确认的消息太多,FCM 会停止发送。因此,应用服务器应尽快“确认”通过 FCM 从客户端应用程序接收到的上游消息,以保持传入消息的恒定流。上述待处理消息限制不适用于这些 ACK。即使待处理的消息计数达到 100,应用服务器也应继续为从 FCM 接收到的消息发送 ACK,以避免阻止新上游消息的传递。

ACK 仅在一个连接的上下文中有效。如果在确认消息之前连接已关闭,则应用服务器应等待 FCM 重新发送上游消息,然后再再次确认。同样,在连接关闭之前未从 FCM 收到 ACK/NACK 的所有未决消息应再次发送。