iOS 카카오톡 링크 안 열림, CORS, Solapi 크레덴셜 순서 문제
프로덕션 릴리스 삽질기 (2026-04-17)
프로젝트: TimeSlot Event OS 날짜: 2026-04-17 (집중 배포 세션)
문제 1 — iOS KakaoTalk 인앱 브라우저에서 링크가 열리지 않음
증상
Solapi 알림톡에서 이벤트 링크 클릭 시 iOS KakaoTalk 인앱 브라우저에서 페이지가 열리지만, Safari로 전환이 되지 않아 일부 기능(특히 Firebase Auth) 동작 불가.
원인
기존 app/open/page.tsx에서 JavaScript로 kakaotalk:// 스킴을 호출하려 했는데,
iOS는 사용자 제스처 없는 JS 스킴 호출을 차단한다.
// 실패하는 방식 — iOS에서 동작 안 함
window.location.href = `kakaotalk://web/openExternal?url=${targetUrl}`;
해결
Cloud Function(openRedirect)으로 서버 사이드 HTTP 302 redirect:
iOS는 JS 스킴은 막지만 HTTP 302 응답의 Location 헤더는 따른다.
// functions/index.js — openRedirect 함수
exports.openRedirect = onRequest(
{ region: "asia-northeast3" },
(req, res) => {
const eventSlug = req.query.e;
const ua = req.get("User-Agent") || "";
const isKakaoTalk = ua.includes("KAKAOTALK");
const isAndroid = ua.includes("Android");
if (isKakaoTalk && !isAndroid) {
// iOS: kakaotalk:// 스킴 — HTTP 302로만 가능
return res.redirect(302,
`kakaotalk://web/openExternal?url=https://timeslot.congkong.net/events/${eventSlug}`
);
}
if (isKakaoTalk && isAndroid) {
// Android: Chrome intent
return res.redirect(302,
`intent://timeslot.congkong.net/events/${eventSlug}#Intent;` +
`scheme=https;package=com.android.chrome;end`
);
}
return res.redirect(302, `/events/${eventSlug}`);
}
);
firebase.json rewrite로 /open 경로를 함수로 연결:
{
"source": "/open",
"function": "openRedirect"
}
핵심: iOS에서 JS로 앱 스킴 열기 = 불가. HTTP 302 = 가능. 반드시 서버 사이드로.
문제 2 — Cloud Functions CORS preflight 오류
증상
Access to fetch at 'https://asia-northeast3-timeslot-99a39.cloudfunctions.net/...' has been blocked by CORS policy
원인
Cloud Functions를 us-central1에서 asia-northeast3으로 리전 이전 후,
lib/firebase.ts의 BULK_SEND_URL, RESEND_NOTIFICATION_URL 등이 구 리전 URL을 사용.
해결
setGlobalOptions({location: "asia-northeast3"})으로 Functions 전체 리전 통일lib/firebase.tsURL 상수 모두asia-northeast3URL로 업데이트cors.json의 허용 오리진 재확인
// lib/firebase.ts
export const BULK_SEND_URL =
"https://asia-northeast3-timeslot-99a39.cloudfunctions.net/bulkSendNotification";
export const RESEND_NOTIFICATION_URL =
"https://asia-northeast3-timeslot-99a39.cloudfunctions.net/resendNotification";
체크리스트: Functions 리전 변경 시 클라이언트 URL 상수도 반드시 함께 변경.
문제 3 — Solapi 알림톡 발송 실패 (API KEY/SECRET 순서 오류)
증상
알림톡 발송 시 401 Unauthorized 오류.
원인
functions/.env에 SOLAPI_API_KEY와 SOLAPI_API_SECRET 값을 반대로 입력.
# 잘못된 설정
SOLAPI_API_KEY=NCS...secret...
SOLAPI_API_SECRET=STA...key...
해결
값 교환 후 재배포. 단순 실수지만 에러 메시지가 401뿐이라 찾기 어려웠음.
방지책: .env.example에 값 예시 형식을 주석으로 남겨두기:
# Solapi — dashboard.solapi.com > 개발자센터 > API Key 관리
SOLAPI_API_KEY=STA로 시작하는 키
SOLAPI_API_SECRET=NCS로 시작하는 시크릿
문제 4 — Solapi IP 화이트리스트 (Cloud Run egress IP)
증상
Cloud Functions에서 Solapi API 호출 시 간헐적 거부.
원인
Solapi 계정에 IP 화이트리스트 설정이 되어있었는데, Cloud Functions가 Cloud Run으로 실행되며 egress IP가 고정되지 않음.
해결
Solapi 대시보드에서 Cloud Run 가능 egress IP 대역을 화이트리스트에 추가. 또는 IP 화이트리스트를 비활성화 (개발 초기라면).
교훈: 외부 API에 IP 화이트리스트가 있다면 서버리스(Cloud Functions/Run) 배포 전에 egress IP 정책 확인 필수.
최종 결과
| 문제 | 원인 | 해결 |
|---|---|---|
| iOS KakaoTalk 외부 브라우저 전환 실패 | JS 스킴 호출 iOS 차단 | Cloud Function HTTP 302 redirect |
| CORS preflight 오류 | 리전 변경 후 URL 미동기화 | 클라이언트 URL 상수 업데이트 |
| Solapi 401 오류 | KEY/SECRET 값 반대로 입력 | 값 교환 후 재배포 |
| Solapi 간헐적 거부 | Cloud Run IP 미등록 | Solapi IP 화이트리스트 추가 |