Catch up on highlights from Firebase at Google I/O 2023. Learn more

您的服務器環境和 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,支持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與應用服務器之間的控制流程詳圖

圖 1.消息/確認流。

相反,為了避免應用服務器過載,如果有太多未確認的消息,FCM 會停止發送。因此,應用服務器應盡快“確認”通過 FCM 從客戶端應用程序接收到的上游消息,以保持傳入消息的持續流動。上述未決消息限制不適用於這些 ACK。即使待處理消息計數達到 100,應用服務器也應繼續為從 FCM 收到的消息發送 ACK,以避免阻止新上游消息的傳遞。

ACK 僅在一個連接的上下文中有效。如果連接在消息可以被確認之前關閉,應用服務器應該等待 FCM 重新發送上游消息,然後再再次確認它。同樣,在關閉連接之前未從 FCM 收到 ACK/NACK 的所有未決消息都應再次發送。