從舊版 FCM API 遷移到 HTTP v1

使用已棄用的 HTTP 和 XMPP FCM 舊版 API 的應用程序應儘早遷移到 HTTP v1 API。除了持續的支持和新功能之外,HTTP v1 API 相對於舊版 API 還具有以下優勢:

  • 通過訪問令牌提高安全性HTTP v1 API 根據 OAuth2 安全模型使用短期訪問令牌。如果訪問令牌公開,它只能被惡意使用一個小時左右,然後就會過期。刷新令牌的傳輸頻率不像舊 API 中使用的安全密鑰那樣頻繁,因此它們被捕獲的可能性要小得多。

  • 跨平台更高效地自定義消息對於消息正文,HTTP v1 API 具有可訪問所有目標實例的通用密鑰,以及可讓您跨平台自定義消息的特定於平台的密鑰。這允許您創建“覆蓋”,在單個消息中將略有不同的有效負載發送到不同的客戶端平台。

  • 新客戶端平台版本的可擴展性更強且面向未來HTTP v1 API 完全支持 Apple 平台、Android 和 Web 上提供的消息傳遞選項。由於每個平台在 JSON 有效負載中都有自己定義的塊,因此 FCM 可以根據需要將 API 擴展到新版本和新平台。

更新服務器端點

HTTP v1 API 的端點 URL 與舊端點的不同之處如下:

  • 它有版本控制,路徑中帶有/v1
  • 該路徑包含您的應用的 Firebase 項目的項目 ID,格式為/projects/myproject-ID/ 。此 ID 可在 Firebase 控制台的常規項目設置選項卡中找到。
  • 它明確指定send方法為:send

要更新 HTTP v1 的服務器端點,請將這些元素添加到發送請求標頭中的端點。

之前的 HTTP 請求

POST https://fcm.googleapis.com/fcm/send

之前的 XMPP 請求

舊版 XMPP 消息通過連接發送到以下端點:

fcm-xmpp.googleapis.com:5235

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send

更新發送請求的授權

HTTP v1 發送請求需要 OAuth 2.0 訪問令牌,而不是舊請求中使用的服務器密鑰字符串。如果您使用 Admin SDK 發送消息,該庫會為您處理令牌。如果您使用的是原始協議,請按照本節中所述獲取令牌,並將其添加到標頭中,格式為Authorization: Bearer <valid Oauth 2.0 token>

Authorization: key=AIzaSyZ-1u...0GBYzPu7Udno5aA

Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA

根據服務器環境的詳細信息,使用以下策略的組合來授權對 Firebase 服務的服務器請求:

  • Google 應用程序默認憑據 (ADC)
  • 服務帳戶 JSON 文件
  • 從服務帳戶派生的短暫 OAuth 2.0 訪問令牌

如果您的應用程序在 Compute Engine、Google Kubernetes Engine、App Engine 或 Cloud Functions(包括 Cloud Functions for Firebase)上運行,請使用應用程序默認憑據 (ADC)。 ADC 使用您現有的默認服務帳戶來獲取憑據來授權請求​​,並且 ADC 通過環境變量GOOGLE_APPLICATION_CREDENTIALS啟用靈活的本地測試。為了實現授權流程的最完全自動化,請將 ADC 與 Admin SDK 服務器庫一起使用。

如果您的應用程序在非 Google 服務器環境上運行,則需要從 Firebase 項目下載服務帳戶 JSON 文件。只要您有權訪問包含私鑰文件的文件系統,就可以使用環境變量GOOGLE_APPLICATION_CREDENTIALS通過這些手動獲取的憑據來授權請求​​。如果您缺乏此類文件訪問權限,則必須在代碼中引用服務帳戶文件 - 由於存在暴露憑據的風險,因此應格外小心。

使用 ADC 提供憑據

Google 應用程序默認憑據 (ADC) 按以下順序檢查您的憑據:

  1. ADC 檢查環境變量GOOGLE_APPLICATION_CREDENTIALS是否已設置。如果設置了該變量,ADC 將使用該變量指向的服務帳戶文件。

  2. 如果未設置環境變量,ADC 將使用 Compute Engine、Google Kubernetes Engine、App Engine 和 Cloud Functions 為在這些服務上運行的應用程序提供的默認服務帳戶。

  3. 如果 ADC 無法使用上述任一憑據,系統將引發錯誤。

以下 Admin SDK 代碼示例說明了此策略。該示例未明確指定應用程序憑據。但是,只要設置了環境變量,或者只要應用程序在 Compute Engine、Google Kubernetes Engine、App Engine 或 Cloud Functions 上運行,ADC 就能夠隱式找到憑據。

Node.js

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
});

爪哇

FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.getApplicationDefault())
    .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
    .build();

FirebaseApp.initializeApp(options);

Python

default_app = firebase_admin.initialize_app()

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C#

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
});

手動提供憑據

Firebase 項目支持 Google服務帳戶,您可以使用它從應用服務器或受信任的環境中調用 Firebase 服務器 API。如果您在本地開發代碼或在本地部署應用程序,則可以使用通過此服務帳戶獲取的憑據來授權服務器請求。

要對服務帳戶進行身份驗證並授權其訪問 Firebase 服務,您必須生成 JSON 格式的私鑰文件。

要為您的服務帳戶生成私鑰文件:

  1. 在 Firebase 控制台中,打開設置 >服務帳戶

  2. 單擊“生成新私鑰” ,然後單擊“生成密鑰”進行確認。

  3. 安全地存儲包含密鑰的 JSON 文件。

通過服務帳戶授權時,您有兩種選擇向應用程序提供憑據。您可以設置GOOGLE_APPLICATION_CREDENTIALS環境變量,也可以在代碼中顯式傳遞服務帳戶密鑰的路徑。第一個選項更安全,強烈推薦。

設置環境變量:

將環境變量GOOGLE_APPLICATION_CREDENTIALS設置為包含服務帳戶密鑰的 JSON 文件的文件路徑。該變量僅適用於當前的 shell 會話,因此如果您打開新會話,請再次設置該變量。

Linux 或 macOS

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

視窗

使用 PowerShell:

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"

完成上述步驟後,應用程序默認憑據 (ADC) 能夠隱式確定您的憑據,從而允許您在非 Google 環境中測試或運行時使用服務帳戶憑據。

使用憑據創建訪問令牌

將您的 Firebase 憑據與您的首選語言的Google Auth 庫一起使用,以檢索短期 OAuth 2.0 訪問令牌:

節點.js

 function getAccessToken() {
  return new Promise(function(resolve, reject) {
    const key = require('../placeholders/service-account.json');
    const jwtClient = new google.auth.JWT(
      key.client_email,
      null,
      key.private_key,
      SCOPES,
      null
    );
    jwtClient.authorize(function(err, tokens) {
      if (err) {
        reject(err);
        return;
      }
      resolve(tokens.access_token);
    });
  });
}

在此示例中,Google API 客戶端庫使用 JSON Web 令牌或 JWT 對請求進行身份驗證。有關更多信息,請參閱JSON Web 令牌

Python

def _get_access_token():
  """Retrieve a valid access token that can be used to authorize requests.

  :return: Access token.
  """
  credentials = service_account.Credentials.from_service_account_file(
    'service-account.json', scopes=SCOPES)
  request = google.auth.transport.requests.Request()
  credentials.refresh(request)
  return credentials.token

爪哇

private static String getAccessToken() throws IOException {
  GoogleCredentials googleCredentials = GoogleCredentials
          .fromStream(new FileInputStream("service-account.json"))
          .createScoped(Arrays.asList(SCOPES));
  googleCredentials.refresh();
  return googleCredentials.getAccessToken().getTokenValue();
}

訪問令牌過期後,會自動調用令牌刷新方法以檢索更新的訪問令牌。

要授權訪問 FCM,請請求範圍https://www.googleapis.com/auth/firebase.messaging

要將訪問令牌添加到 HTTP 請求標頭:

將令牌添加為Authorization標頭的值,格式為Authorization: Bearer <access_token>

節點.js

headers: {
  'Authorization': 'Bearer ' + accessToken
}

Python

headers = {
  'Authorization': 'Bearer ' + _get_access_token(),
  'Content-Type': 'application/json; UTF-8',
}

爪哇

URL url = new URL(BASE_URL + FCM_SEND_ENDPOINT);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestProperty("Authorization", "Bearer " + getServiceAccountAccessToken());
httpURLConnection.setRequestProperty("Content-Type", "application/json; UTF-8");
return httpURLConnection;

更新發送請求的負載

FCM HTTP v1 在 JSON 消息負載的結構中引入了重大變化。主要是,這些更改確保在不同客戶端平台上接收消息時能夠正確處理消息;此外,這些更改為您提供了額外的靈活性,可以自定義或“覆蓋”每個平台的消息字段。

除了檢查本節中的示例之外,請參閱跨平台自定義消息並查看API 參考以熟悉 HTTP v1。

示例:簡單的通知消息

下面是一個非常簡單的通知有效負載(僅包含titlebodydata字段)的比較,展示了舊版有效負載和 HTTP v1 有效負載的根本區別。

{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available."
  },
  "data": {
    "story_id": "story_12345"
  }
}

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    }
  }
}

示例:針對多個平台

為了實現多平台定位,舊版 API 在後端執行了覆蓋。相比之下,HTTP v1 提供了特定於平台的密鑰塊,使平台之間的任何差異對開發人員來說都是明確可見的。這允許您始終通過單個請求定位多個平台,如以下示例所示。

// Android
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "TOP_STORY_ACTIVITY"
  },
  "data": {
    "story_id": "story_12345"
  }
}
// Apple
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "HANDLE_BREAKING_NEWS"
  },
  "data": {
    "story_id": "story_12345"
  }
}

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    },
    "android": {
      "notification": {
        "click_action": "TOP_STORY_ACTIVITY"
      }
    },
    "apns": {
      "payload": {
        "aps": {
          "category" : "NEW_MESSAGE_CATEGORY"
        }
      }
    }
  }
}

示例:使用平台覆蓋進行自定義

除了簡化消息的跨平台定位之外,HTTP v1 API 還提供了根據平台自定義消息的靈活性。

// Android
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "Check out the Top Story.",
    "click_action": "TOP_STORY_ACTIVITY"
  },
  "data": {
    "story_id": "story_12345"
  }
}
// Apple
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "HANDLE_BREAKING_NEWS"
  },
  "data": {
    "story_id": "story_12345"
  }
}

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    },
    "android": {
      "notification": {
        "click_action": "TOP_STORY_ACTIVITY",
        "body": "Check out the Top Story"
      }
    },
    "apns": {
      "payload": {
        "aps": {
          "category" : "NEW_MESSAGE_CATEGORY"
        }
      }
    }
  }
}

示例:針對特定設備

要使用 HTTP v1 API 定位特定設備,請在token鍵(而不是to鍵)中提供設備的當前註冊令牌。

  { "notification": {
      "body": "This is an FCM notification message!",
      "time": "FCM Message"
    },
    "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
  }

{
   "message":{
      "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
      "notification":{
        "body":"This is an FCM notification message!",
        "title":"FCM Message"
      }
   }
}

有關 FCM HTTP v1 API 的更多示例和信息,請參閱以下內容: