Save the date - Google I/O returns May 18-20. Register to get the most out of the digital experience: Build your schedule, reserve space, participate in Q&As, earn Google Developer profile badges, and more. Register now
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

從舊版HTTP遷移到HTTP v1

使用FCM舊式HTTP API的應用應考慮按照本指南中的說明遷移到HTTP v1 API。與舊版API相比,HTTP v1 API具有以下優勢:

  • 通過訪問令牌提供更好的安全性HTTP v1 API根據OAuth2安全模型使用短期訪問令牌。如果訪問令牌公開,則只能在一個小時左右的時間內被惡意使用。刷新令牌的傳輸頻率不如舊版API中使用的安全密鑰,因此捕獲令牌的可能性要小得多。

  • 跨平台更有效地定制消息對於消息主體,HTTP v1 API具有可用於所有目標實例的通用密鑰,以及可用於跨平台定制消息的特定於平台的密鑰。這使您可以創建“替代”,從而在一條消息中將略有不同的有效負載發送到不同的客戶端平台。

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

更新服務器端點

HTTP v1 API的端點URL在以下方面與舊式端點有所不同:

  • 已對其進行版本控制,路徑中帶有/v1
  • 該路徑包含您的應用程序的Firebase項目的項目ID,格式為/projects/myproject-ID/ 。該ID在Firebase控制台的“常規項目設置”選項卡中可用。
  • 它顯式指定將send方法指定為:send

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

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

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引擎,App Engine或云功能(包括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 API客戶端庫一起用於您的首選語言,以檢索短暫的OAuth 2.0訪問令牌:

node.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網絡令牌或JWT對請求進行身份驗證。有關更多信息,請參閱JSON Web令牌

Python

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

  :return: Access token.
  """
  credentials = ServiceAccountCredentials.from_json_keyfile_name(
      'service-account.json', SCOPES)
  access_token_info = credentials.get_access_token()
  return access_token_info.access_token

爪哇

private static String getAccessToken() throws IOException {
  GoogleCredential googleCredential = GoogleCredential
      .fromStream(new FileInputStream("service-account.json"))
      .createScoped(Arrays.asList(SCOPES));
  googleCredential.refreshToken();
  return googleCredential.getAccessToken();
}

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

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

要將訪問令牌添加到HTTP請求標頭中,請執行以下操作:

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

node.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 " + getAccessToken());
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"
  }
}
// iOS
{
  "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"
  }
}
// iOS
{
  "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"
        }
      }
    }
  }
}

有關FCM HTTP v1 API的更多示例和信息,請參閱Firebase博客