Firebase 클라우드 메시징 서버 정보

Firebase 클라우드 메시징의 서버 쪽 구성요소는 2가지입니다.

앱 서버 또는 신뢰할 수 있는 서버 환경에서는 FCM 서버에 메시지 요청을 보내고, FCM 서버는 사용자 기기에서 실행되는 클라이언트 앱에 메시지를 보냅니다.

클라이언트 측에서 구현하는 방법에 대해서는 iOS, Android 또는 등 플랫폼별 클라이언트 가이드를 참조하세요.

신뢰할 수 있는 서버 환경의 역할

Firebase 클라우드 메시징을 사용하는 클라이언트 앱을 작성하려면 먼저 다음 조건을 충족하는 서버 환경을 갖춰야 합니다.

  • 클라이언트와 통신할 수 있습니다.
  • FCM 서버에 올바르게 형식이 지정된 메시지 요청을 보낼 수 있습니다.
  • 지수 백오프를 사용하여 요청을 처리하고 다시 보낼 수 있습니다.
  • 서버 키와 클라이언트 등록 토큰을 안전하게 저장할 수 있습니다. 참고: 클라이언트 코드에 절대로 서버 키를 포함해서는 안 됩니다.
  • XMPP의 경우 전송하는 각 메시지를 고유하게 구별하기 위해 서버에서 메시지 ID를 생성할 수 있어야 합니다. FCM HTTP 연결 서버는 메시지 ID를 생성하여 응답에서 반환합니다. XMPP 메시지 ID는 발신자 ID별로 고유해야 합니다.

FCM 서버와 상호작용할 방법을 결정해야 합니다. Admin SDK 또는 원시 프로토콜을 사용할 수 있습니다. 원시 프로토콜 옵션 중에서 FCM HTTP v1 API는 가장 최신 프로토콜로서 보다 안전한 인증과 유연한 교차 플랫폼 메시징 기능을 제공합니다. 이전의 HTTPXMPP 서버 프로토콜 영역도 사용할 수 있습니다. 클라이언트 애플리케이션에서 업스트림 메시징을 사용하려면 XMPP를 사용해야 합니다. 자세한 내용은 FCM 서버 프로토콜을 참조하세요.

FCM 서버 프로토콜

현재 FCM은 다음과 같은 원시 서버 프로토콜을 제공합니다.

앱 서버는 이러한 프로토콜을 별도로 사용하거나 동시에 사용할 수 있습니다. 가능하면 여러 플랫폼에 메시지를 보낼 수 있는 유연한 최신 프로토콜인 FCM HTTP v1 API를 사용하는 것이 좋습니다. 기기에서 서버로 업스트림 메시지를 보낼 필요가 있는 경우에는 XMPP 프로토콜을 구현해야 합니다.

XMPP 메시징은 다음 방식에 있어서 HTTP 메시징과 다릅니다.

  • 업스트림/다운스트림 메시지
    • HTTP: 클라우드에서 기기로 전송하는 다운스트림 전용
    • XMPP: 기기에서 클라우드로 전송하는 업스트림 및 클라우드에서 기기로 전송하는 다운스트림
  • 메시징(동기 또는 비동기)
    • HTTP: 동기 메시징입니다. 앱 서버가 HTTP POST 요청으로 메시지를 보내고 응답을 기다립니다. 이 방식은 동기 메시징이며 응답이 수신될 때까지 발신자가 다른 메시지를 보내지 못하도록 차단합니다.
    • XMPP: 비동기 메시징입니다. 앱 서버가 영구 XMPP 연결을 통해 최대 회선 속도로 모든 기기에서 양방향으로 메시지를 주고받습니다. XMPP 연결 서버가 확인 또는 실패 알림을 비동기 방식으로 보냅니다. 확인 형식은 JSON으로 인코딩된 특수한 ACK 및 NACK XMPP 메시지입니다.
  • JSON
    • HTTP: JSON 메시지는 HTTP POST로 전송됩니다.
    • XMPP: JSON 메시지는 XMPP 메시지에 캡슐화됩니다.
  • 일반 텍스트
    • HTTP: 일반 텍스트 메시지는 HTTP POST로 전송됩니다.
    • XMPP: 지원되지 않습니다.
  • 여러 등록 토큰에 전송되는 멀티캐스트 다운스트림
    • HTTP: JSON 메시지 형식으로 지원됩니다.
    • XMPP: 지원되지 않습니다.

HTTP 서버 프로토콜 구현

메시지를 보내려면 앱 서버에서 JSON 키-값 쌍으로 구성된 HTTP 헤더와 HTTP 본문을 포함하는 POST 요청을 만듭니다. 헤더 및 본문의 옵션에 관한 자세한 내용은 앱 서버 보내기 요청 작성을 참조하세요.

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를 보내지 않으면 이 메시지가 먼저 만료되지 않는 한 다음에 새로운 XMPP 연결이 설정될 때 FCM이 메시지를 다시 보냅니다.

또한 서버에서 기기로 전송한 메시지별로 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>

페이로드가 포함된 메시지 - 데이터 메시지

다음은 앱 서버에서 FCM으로 보내는 JSON 메시지가 포함된 XMPP 스탠자입니다.

<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",
      "delivery_receipt_requested": true/false
  }
  </gcm>
</message>

응답 형식

FCM 응답으로 가능한 형식은 세 가지입니다. 첫 번째는 일반적인 'ack' 메시지입니다. 그러나 응답에 오류가 포함된 경우 메시지는 다음과 같은 두 가지 형식을 취할 수 있습니다.

ACK 메시지

다음은 FCM에서 앱 서버로 보내는 ACK 또는 NACK 메시지가 포함된 XMPP 스탠자입니다.

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "from":"REGID",
      "message_id":"m-1366082849205"
      "message_type":"ack"
  }
  </gcm>
</message>

NACK 메시지

NACK 오류는 message_type 상태 메시지가 'nack'인 일반적인 XMPP 메시지입니다. NACK 메시지에는 다음이 포함됩니다.

  • NACK 오류 코드
  • NACK 오류 설명

아래는 몇 가지 예입니다.

잘못된 등록:

<message>
  <gcm xmlns="google:mobile:data">
  {
    "message_type":"nack",
    "message_id":"msgId1",
    "from":"SomeInvalidRegistrationId",
    "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 오류 코드의 전체 목록은 서버 참조를 확인하세요. 별도로 표시되어 있지 않으면 NACK 상태인 메시지를 다시 시도해서는 안 됩니다. 예상하지 못한 NACK 오류 코드는 INTERNAL_SERVER_ERROR와 동일하게 처리해야 합니다.

스탠자 오류

특정 상황에서는 스탠자 오류가 발생할 수도 있습니다. 스탠자 오류에는 다음이 포함됩니다.

  • 스탠자 오류 코드
  • 스탠자 오류 설명(자유로운 텍스트 형식)

예를 들면 다음과 같습니다.

<message id="3" type="error" to="123456789@gcm.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 메시지를 보내 연결이 드레이닝 되는 중이며 곧 종료된다고 알립니다. '드레이닝'이란 연결로 유입되는 메시지 흐름이 종료되지만 이미 파이프라인에 있는 메시지는 계속해서 처리됨을 의미합니다. CONNECTION_DRAINING 메시지가 수신되면 즉시 다른 FCM 연결로 메시지를 보내야 하며 필요한 경우 새 연결을 열어야 합니다. 하지만 원래 연결은 열려 있는 상태로 유지하여 이 연결을 통해 수신될 수 있는 메시지를 계속 수신하고 ACK 처리해야 합니다. 준비가 완료되면 FCM이 연결 종료를 시작하는 작업을 처리합니다.

CONNECTION_DRAINING 메시지는 다음과 같이 표시됩니다.

<message>
  <data:gcm xmlns:data="google:mobile:data">
  {
    "message_type":"control"
    "control_type":"CONNECTION_DRAINING"
  }
  </data:gcm>
</message>

현재 지원되는 control_typeCONNECTION_DRAINING뿐입니다.

전송 확인 수신

Android와 Chrome 클라이언트 앱의 경우 기기가 FCM에서 전송된 메시지를 수신했음을 확인하면 FCM에서 앱 서버로 보내는 전송 확인을 받을 수 있습니다.

이 기능을 사용 설정하려면 앱 서버가 FCM에 보내는 메시지에 delivery_receipt_requested 필드가 포함되어야 합니다. 이 필드가 true로 설정된 경우 기기가 특정 메시지를 수신했다고 확인하면 FCM이 전송 확인을 전송합니다.

다음은 "delivery_receipt_requested"true로 설정된 JSON 메시지가 포함된 XMPP 스탠자입니다.

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "to":"REGISTRATION_ID",
      "message_id":"m-1366082849205"
      "data":
      {
          "hello":"world",
      }
      "time_to_live":"600",
      "delivery_receipt_requested": true
  }
  </gcm>
</message>

다음은 기기가 FCM에서 보낸 메시지를 수신했음을 알리기 위해 FCM이 앱 서버로 보내는 전송 확인의 예입니다.

<message id="">
  <gcm xmlns="google:mobile:data">
  {
      "category":"com.example.yourapp", // to know which app sent it
      "data":
      {
         “message_status":"MESSAGE_SENT_TO_DEVICE",
         “original_message_id”:”m-1366082849205”
         “device_registration_id”: “REGISTRATION_ID”
      },
      "message_id":"dr2:m-1366082849205",
      "message_type":"receipt",
      "from":"gcm.googleapis.com"
  }
  </gcm>
</message>

다음에 유의하세요.

  • "message_type""receipt"로 설정되어 있습니다.
  • "message_status""MESSAGE_SENT_TO_DEVICE"로 설정되어 있으며 기기가 메시지가 수신했음을 나타냅니다. 이 사례에서 "message_status"가 필드가 아닌 데이터 페이로드의 일부라는 점에 유의하세요.
  • 확인 메시지 ID는 원래 메시지 ID로 구성되지만 dr2: 프리픽스가 추가됩니다. 앱 서버는 같은 연결을 사용하여 이 ID와 함께 ACK를 돌려보내야 합니다. 이 예에서는 dr2:m-1366082849205입니다.
  • 원래 메시지 ID, 기기 등록 토큰, 상태는 "data" 필드 내에 있습니다.
  • FCM과 기기의 연결 상태가 좋지 않으면 Firebase 클라우드 메시징에서 중복된 전송 확인을 여러 번 보낼 수 있습니다. 이러한 중복 확인은 무시해도 됩니다.

흐름 관리

FCM으로 보낸 모든 메시지는 ACK 또는 NACK 응답을 받습니다. 이러한 응답을 받지 못한 메시지는 대기 중인 것으로 간주됩니다. 대기 중인 메시지 수가 100개에 도달하면 앱 서버에서 메시지를 새로 보내는 것을 중지하고 그림 1에 나와 있는 것처럼 FCM이 대기 중인 기존 메시지 중 일부를 확인할 때까지 기다려야 합니다.

그림 1. 메시지 ACK 흐름

반대로, 확인되지 않은 메시지가 너무 많으면 앱 서버에 과부하가 발생하지 않도록 FCM이 전송을 중지합니다. 따라서 FCM을 통해 클라이언트 애플리케이션으로부터 수신한 업스트림 메시지를 앱 서버에서 최대한 빠르게 'ACK' 처리하여 수신 메시지의 흐름을 일정하게 유지해야 합니다. 이러한 ACK에는 앞서 설명한 대기 중인 메시지의 한도가 적용되지 않습니다. 대기 중인 메시지 수가 100개에 도달해도 새로운 업스트림 메시지의 전송이 차단되지 않도록 앱 서버가 FCM에서 수신한 메시지에 대해 계속 ACK를 보내야 합니다.

ACK는 연결 1개 내에서만 유효합니다. 메시지를 ACK 처리하기 전에 연결이 종료되면 다시 ACK 처리하기 전에 FCM에서 업스트림 메시지를 다시 보낼 때까지 앱 서버에서 대기해야 합니다. 마찬가지로 연결이 종료되기 전에 FCM에서 ACK 또는 NACK가 수신되지 않은 대기 중인 모든 메시지도 다시 보내야 합니다.

다음에 대한 의견 보내기...

도움이 필요하시나요? 지원 페이지를 방문하세요.