您的服務器環境和 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 的所有未決消息應再次發送。