FCM 토픽에 한글이 안 된다고? URL 인코딩으로 제한 뚫기

최근 마케팅 팀 요청으로 세분화된 타겟 푸시 기능을 개발하던 중, 운영 환경 로그에서 java.lang.IllegalArgumentException: Invalid topic name 예외가 쏟아지는 현상을 목격했습니다. 원인은 간단했습니다. 마케팅 대시보드에서 입력한 토픽 이름이 '긴급공지'였기 때문입니다. FCM(Firebase Cloud Messaging)은 토픽 이름에 한글을 허용하지 않습니다. 이 글에서는 별도의 매핑 테이블(DB) 관리 없이, 표준 인코딩 기술만으로 이 제약을 우회하여 운영 효율을 극대화한 경험을 공유합니다.

Regex 제약 분석과 우회 전략

문제의 핵심은 FCM이 정의한 토픽 네이밍 규칙에 있습니다. 공식 문서를 뜯어보면 토픽 이름은 다음 정규 표현식을 만족해야 합니다.

FCM Topic Regex Rule: [a-zA-Z0-9-_.~%]

이 규칙에 따르면 한글, 공백, 특수문자 대부분이 차단됩니다. 보통 개발자들은 이를 해결하기 위해 두 가지 방법을 사용합니다.

  1. 로마자 표기: '뉴스' → 'news', '공지' → 'notice'
  2. 매핑 테이블: DB에 ID: 101, Name: "이벤트"를 저장하고 토픽을 'topic_101'로 구독.

하지만 1번은 가독성이 떨어지고, 2번은 관리 포인트가 늘어납니다. 여기서 주목할 점은 정규식 마지막에 허용된 퍼센트 기호(%)입니다. 웹 표준 기술인 URL Encoding(Percent Encoding)을 사용하면 한글을 %로 시작하는 문자열로 변환할 수 있습니다. 즉, FCM의 제약을 위반하지 않으면서 한글의 의미를 유지할 수 있는 유일한 통로입니다.

The Solution: Encoding Pipeline

해결책은 클라이언트(구독)와 서버(발송) 양쪽에서 토픽 이름을 인코딩/디코딩하는 파이프라인을 구축하는 것입니다. 아래는 Android 클라이언트와 Java 백엔드에서의 구현 예시입니다.

참고: iOS(Swift)나 Web(JS)에서도 동일하게 UTF-8 기반의 URL 인코딩 함수를 사용하면 플랫폼 간 호환성 문제가 없습니다.
// [Android Client] Topic 구독 로직
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import com.google.firebase.messaging.FirebaseMessaging

fun subscribeToKoreanTopic(rawTopic: String) {
    try {
        // 1. 한글을 UTF-8 URL 인코딩 변환
        // 예: "뉴스" -> "%EB%89%B4%EC%8A%A4"
        val encodedTopic = URLEncoder.encode(rawTopic, StandardCharsets.UTF_8.toString())
        
        // 2. FCM 구독 요청
        FirebaseMessaging.getInstance().subscribeToTopic(encodedTopic)
            .addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    // 성공 로그
                }
            }
    } catch (e: Exception) {
        // 인코딩 실패 예외 처리
    }
}

// [Backend Server] 메시지 발송 로직 (Java)
public void sendFCMMessage(String koreanTopic, String messageBody) {
    try {
        // 서버에서도 동일하게 인코딩하여 타겟 지정
        String targetTopic = URLEncoder.encode(koreanTopic, StandardCharsets.UTF_8);
        
        Message message = Message.builder()
            .setTopic(targetTopic) // 인코딩된 토픽 사용
            .putData("body", messageBody)
            .build();
            
        FirebaseMessaging.getInstance().send(message);
        
    } catch (Exception e) {
        log.error("FCM Send Error", e);
    }
}

Performance & Strategy Comparison

URL 인코딩 방식이 기존의 매핑 방식보다 아키텍처 관점에서 얼마나 효율적인지 비교해 보았습니다.

비교 항목 DB 매핑 방식 (Legacy) URL 인코딩 방식 (Recommended)
구현 복잡도 High (별도 테이블, API 필요) Low (유틸리티 함수 호출)
데이터 일관성 DB 동기화 문제 발생 가능 Stateless (변환 로직만 존재)
디버깅 용이성 ID(1042)만 보고 내용 파악 불가 디코딩 시 즉시 원문 확인 가능
운영 비용 DB 조회 비용 발생 CPU 연산 비용 미미함
주의사항: 인코딩된 문자열이 매우 길어질 경우 FCM의 토픽 길이 제한(현재 900자 이상 지원하므로 대부분 안전함)을 초과하지 않는지 확인해야 합니다. 일반적인 단어 수준에서는 문제되지 않습니다.

Conclusion

FCM의 정규식 제약 때문에 한글 토픽을 포기하거나 복잡한 매핑 테이블을 만드는 것은 오버엔지니어링입니다. % 문자가 허용된다는 점을 이용해 URL 인코딩을 적용하면, 개발 생산성을 유지하면서도 운영팀이 원하는 직관적인 한글 키워드를 그대로 사용할 수 있습니다. 지금 바로 프로젝트의 레거시 코드를 확인해 보세요. 불필요한 매핑 로직을 걷어낼 기회일지도 모릅니다.

1 comment

  1. 하진짜 제 영웅이십니다 FCM 한글꺠짐때문에 얼마나 고생헀는지 모릅니다 ㅠㅠ 감사합니다

    ReplyDelete