Di chuyển từ API FCM cũ sang HTTP phiên bản 1

Các ứng dụng đang dùng API cũ FCM không dùng nữa cho HTTP và XMPP nên di chuyển sang API HTTP phiên bản 1 trong thời gian sớm nhất. Việc gửi thông báo (bao gồm cả thông báo ngược dòng) bằng các API đó không còn được dùng nữa kể từ ngày 20 tháng 6 năm 2023 và hoạt động ngừng hoạt động sẽ bắt đầu từ ngày 22 tháng 7 năm 2024.

Tìm hiểu thêm về các tính năng cụ thể bị ảnh hưởng.

Ngoài việc hỗ trợ liên tục và các tính năng mới, API HTTP v1 còn có những ưu điểm sau so với các API cũ:

  • Tăng cường bảo mật thông qua mã truy cập API HTTP phiên bản 1 sử dụng mã truy cập ngắn hạn theo mô hình bảo mật OAuth2. Trong trường hợp mã thông báo truy cập trở thành công khai, mã này chỉ có thể được sử dụng một cách sai trái trong khoảng một giờ trước khi hết hạn. Mã thông báo làm mới không được truyền thường xuyên như khoá bảo mật được sử dụng trong API cũ, vì vậy, chúng ít có khả năng bị thu thập hơn.

  • Tuỳ chỉnh thông báo hiệu quả hơn trên các nền tảng Đối với nội dung thông báo, API HTTP phiên bản 1 có các khoá phổ biến chuyển đến tất cả các thực thể được nhắm mục tiêu, cùng với các khoá dành riêng cho nền tảng cho phép bạn tuỳ chỉnh thông báo trên các nền tảng. Điều này cho phép bạn tạo "lệnh ghi đè" để gửi tải trọng hơi khác nhau đến các nền tảng ứng dụng trong một thông báo.

  • Có thể mở rộng và phù hợp với tương lai hơn cho các phiên bản nền tảng ứng dụng mới API HTTP v1 hỗ trợ đầy đủ các tuỳ chọn nhắn tin có trên các nền tảng của Apple, Android và Web. Vì mỗi nền tảng đều có khối được xác định riêng trong tải trọng JSON, nên FCM có thể mở rộng API sang các phiên bản mới và nền tảng mới nếu cần.

Cập nhật điểm cuối của máy chủ

URL điểm cuối của API HTTP phiên bản 1 khác với điểm cuối cũ ở những điểm sau:

  • Tệp này được tạo phiên bản, với /v1 trong đường dẫn.
  • Đường dẫn này chứa mã dự án của dự án Firebase cho ứng dụng của bạn, ở định dạng /projects/myproject-ID/. Mã này có trong thẻ Cài đặt chung của dự án của bảng điều khiển Firebase.
  • Tham số này chỉ định rõ phương thức send:send.

Để cập nhật điểm cuối máy chủ cho HTTP phiên bản 1, hãy thêm các phần tử này vào điểm cuối trong tiêu đề của yêu cầu gửi.

Các yêu cầu HTTP trước đó

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

Yêu cầu XMPP trước đó

Thông báo XMPP cũ được gửi qua kết nối đến điểm cuối sau:

fcm-xmpp.googleapis.com:5235

Sau

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

Cập nhật trạng thái cho phép gửi yêu cầu

Thay vì chuỗi khoá máy chủ được dùng trong các yêu cầu cũ, các yêu cầu gửi HTTP phiên bản 1 yêu cầu mã truy cập OAuth 2.0. Nếu bạn đang sử dụng SDK quản trị để gửi thông báo, thì thư viện sẽ xử lý mã thông báo cho bạn. Nếu bạn đang sử dụng giao thức thô của eef, hãy lấy mã thông báo như mô tả trong phần này và thêm mã thông báo đó vào tiêu đề dưới dạng Authorization: Bearer <valid Oauth 2.0 token>.

Trước

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

Sau

Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA

Tuỳ thuộc vào thông tin chi tiết về môi trường máy chủ, hãy sử dụng kết hợp các chiến lược sau để uỷ quyền cho các yêu cầu máy chủ đến các dịch vụ Firebase:

  • Thông tin xác thực mặc định của ứng dụng trên Google (ADC)
  • Tệp JSON của tài khoản dịch vụ
  • Mã truy cập OAuth 2.0 có thời hạn ngắn bắt nguồn từ tài khoản dịch vụ

Nếu ứng dụng của bạn đang chạy trên Compute Engine, Google Kubernetes Engine, App Engine hoặc Cloud Functions (bao gồm cả Cloud Functions for Firebase), hãy sử dụng Thông tin xác thực mặc định của ứng dụng (ADC). ADC sử dụng tài khoản dịch vụ mặc định hiện có của bạn để lấy thông tin xác thực nhằm uỷ quyền cho các yêu cầu. Ngoài ra, ADC cho phép kiểm thử linh hoạt trên máy thông qua biến môi trường GOOGLE_APPLICATION_CREDENTIALS. Để tự động hoá tối đa quy trình uỷ quyền, hãy sử dụng ADC cùng với các thư viện máy chủ SDK quản trị.

Nếu ứng dụng của bạn đang chạy trên môi trường máy chủ không phải của Google, bạn cần tải tệp JSON của tài khoản dịch vụ xuống từ dự án Firebase. Miễn là bạn có quyền truy cập vào hệ thống tệp chứa tệp khoá riêng tư, bạn có thể sử dụng biến môi trường GOOGLE_APPLICATION_CREDENTIALS để uỷ quyền cho các yêu cầu bằng thông tin xác thực thu thập được theo cách thủ công. Nếu không có quyền truy cập vào tệp như vậy, bạn phải tham chiếu tệp tài khoản dịch vụ trong mã của mình. Bạn cần phải thực hiện việc này một cách cực kỳ cẩn thận do có nguy cơ lộ thông tin xác thực của bạn.

Cung cấp thông tin đăng nhập qua ADC

Thông tin xác thực mặc định của ứng dụng Google (ADC) sẽ kiểm tra thông tin xác thực của bạn theo thứ tự sau:

  1. ADC sẽ kiểm tra xem biến môi trường GOOGLE_APPLICATION_CREDENTIALS đã được đặt hay chưa. Nếu bạn đặt biến này, ADC sẽ sử dụng tệp tài khoản dịch vụ mà biến này trỏ đến.

  2. Nếu bạn không đặt biến môi trường, ADC sẽ sử dụng tài khoản dịch vụ mặc định mà Compute Engine, Google Kubernetes Engine, App Engine và Cloud Functions cung cấp cho các ứng dụng chạy trên các dịch vụ đó.

  3. Nếu ADC không thể sử dụng một trong hai thông tin xác thực trên, hệ thống sẽ gửi lỗi.

Ví dụ về mã SDK quản trị sau đây minh hoạ chiến lược này. Ví dụ này không chỉ định rõ thông tin xác thực ứng dụng. Tuy nhiên, ADC có thể tìm thông tin xác thực ngầm ẩn miễn là bạn đặt biến môi trường hoặc miễn là ứng dụng đang chạy trên Compute Engine, Google Kubernetes Engine, App Engine hoặc Cloud Functions.

Node.js

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

Java

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

FirebaseApp.initializeApp(options);

Python

default_app = firebase_admin.initialize_app()

Tiến hành

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(),
});

Cung cấp thông tin xác thực theo cách thủ công

Các dự án Firebase hỗ trợ tài khoản dịch vụ của Google. Bạn có thể sử dụng tài khoản này để gọi API máy chủ Firebase từ máy chủ ứng dụng hoặc môi trường đáng tin cậy. Nếu đang phát triển mã cục bộ hoặc triển khai ứng dụng tại chỗ, bạn có thể sử dụng thông tin xác thực thu được thông qua tài khoản dịch vụ này để uỷ quyền cho các yêu cầu máy chủ.

Để xác thực tài khoản dịch vụ và uỷ quyền cho tài khoản đó truy cập vào các dịch vụ của Firebase, bạn phải tạo một tệp khoá riêng tư ở định dạng JSON.

Cách tạo tệp khoá riêng tư cho tài khoản dịch vụ:

  1. Trong bảng điều khiển của Firebase, hãy mở Cài đặt > Tài khoản dịch vụ.

  2. Nhấp vào Tạo khoá riêng tư mới, rồi xác nhận bằng cách nhấp vào Tạo khoá.

  3. Lưu trữ an toàn tệp JSON chứa khoá.

Khi uỷ quyền thông qua tài khoản dịch vụ, bạn có hai lựa chọn để cung cấp thông tin xác thực cho ứng dụng của mình. Bạn có thể đặt biến môi trường GOOGLE_APPLICATION_CREDENTIALS hoặc truyền rõ ràng đường dẫn đến khoá tài khoản dịch vụ trong mã. Bạn nên chọn phương thức đầu tiên vì phương thức này an toàn hơn.

Cách đặt biến môi trường:

Đặt biến môi trường GOOGLE_APPLICATION_CREDENTIALS thành đường dẫn tệp của tệp JSON chứa khoá tài khoản dịch vụ của bạn. Biến này chỉ áp dụng cho phiên shell hiện tại, vì vậy, nếu bạn mở một phiên mới, hãy đặt lại biến.

Linux hoặc macOS

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

Windows

Với PowerShell:

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

Sau khi bạn hoàn tất các bước trên, Thông tin xác thực mặc định của ứng dụng (ADC) có thể xác định ngầm thông tin xác thực của bạn, cho phép bạn sử dụng thông tin xác thực tài khoản dịch vụ khi kiểm thử hoặc chạy trong môi trường không phải của Google.

Dùng thông tin xác thực để đúc mã truy cập

Sử dụng thông tin xác thực Firebase cùng với Thư viện xác thực của Google cho ngôn ngữ bạn muốn để truy xuất mã truy cập OAuth 2.0 có thời hạn ngắn:

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);
    });
  });
}

Trong ví dụ này, thư viện ứng dụng API của Google xác thực yêu cầu bằng mã thông báo web JSON (JWT). Để biết thêm thông tin, hãy xem bài viết Mã thông báo web JSON.

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

Java

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();
}

Sau khi mã truy cập của bạn hết hạn, phương thức làm mới mã thông báo sẽ được gọi tự động để truy xuất mã truy cập đã cập nhật.

Để uỷ quyền truy cập vào FCM, hãy yêu cầu phạm vi https://www.googleapis.com/auth/firebase.messaging.

Cách thêm mã truy cập vào tiêu đề yêu cầu HTTP:

Thêm mã thông báo làm giá trị của tiêu đề Authorization ở định dạng Authorization: Bearer <access_token>:

node.js

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

Python

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

Java

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;

Cập nhật tải trọng của các yêu cầu gửi

FCM HTTP phiên bản 1 có sự thay đổi đáng kể về cấu trúc của tải trọng thông báo JSON. Chủ yếu, những thay đổi này đảm bảo rằng thư được xử lý chính xác khi nhận được trên các nền tảng ứng dụng khác nhau; ngoài ra, các thay đổi này giúp bạn linh hoạt hơn trong việc tuỳ chỉnh hoặc "ghi đè" các trường thư trên mỗi nền tảng.

Ngoài việc kiểm tra các ví dụ trong phần này, hãy xem Tuỳ chỉnh thông báo trên các nền tảng và xem lại tài liệu tham khảo API để làm quen với HTTP phiên bản 1.

Ví dụ: thông báo đơn giản

Dưới đây là thông tin so sánh về một tải trọng thông báo rất đơn giản – chỉ chứa các trường title, bodydata – minh hoạ những điểm khác biệt cơ bản giữa tải trọng cũ và tải trọng HTTP phiên bản 1.

Trước

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

Sau

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

Ví dụ: dữ liệu JSON lồng nhau

Không giống như API nhắn tin cũ, API HTTP phiên bản 1 không hỗ trợ các giá trị JSON lồng nhau trong trường data. Bạn phải chuyển đổi từ JSON thành chuỗi.

Trước

{
  ...
  "data": {
    "keysandvalues": {"key1": "value1", "key2": 123}
  }
}

Sau

{
  "message": {
   ...
    "data": {
      "keysandvalues": "{\"key1\": \"value1\", \"key2\": 123}"
    }
  }
}

Ví dụ: nhắm đến nhiều nền tảng

Để bật tính năng nhắm mục tiêu nhiều nền tảng, API cũ đã thực hiện các thao tác ghi đè trong phần phụ trợ. Ngược lại, HTTP phiên bản 1 cung cấp các khối khoá dành riêng cho nền tảng, giúp nhà phát triển thấy rõ mọi sự khác biệt giữa các nền tảng. Điều này cho phép bạn luôn nhắm đến nhiều nền tảng bằng một yêu cầu duy nhất, như minh hoạ trong mẫu sau.

Trước

// 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"
  }
}

Sau

{
  "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"
        }
      }
    }
  }
}

Ví dụ: tuỳ chỉnh bằng cơ chế ghi đè nền tảng

Ngoài việc đơn giản hoá việc nhắm mục tiêu thông báo trên nhiều nền tảng, API HTTP phiên bản 1 còn giúp bạn linh hoạt tuỳ chỉnh thông báo theo từng nền tảng.

Trước

// 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"
  }
}

Sau

{
  "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"
        }
      }
    }
  }
}

Ví dụ: nhắm đến các thiết bị cụ thể

Để nhắm đến các thiết bị cụ thể bằng API HTTP v1, hãy cung cấp mã thông báo đăng ký hiện tại của thiết bị trong khoá token thay vì khoá to.

Trước

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

Sau

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

Để biết thêm mẫu và thông tin về API FCM HTTP v1, hãy xem những nội dung sau: