코딩 공부

Web Push API에서 사용자 맞춤 알림 구독/구분/취소 기능 구현하기

새혀니 2025. 3. 24. 21:23

 

  • Web Push 구독 정보를 사용자별로 저장하고 구분하는 방법
  • 실무에서 필요한 “구독 취소” 기능 추가
  • 알림 수신 여부를 제어하는 UI 구성

lib/db.js (메모리 대신 구독 정보 DB로 관리 )

export const subscriptions = [];

pages/api/subscribe.js (사용자 ID와 함께 구독 등록)

import { subscriptions } from '../../lib/db'; export default function handler(req, res) { if (req.method === 'POST') { const { userId, subscription } = req.body; const exists = subscriptions.find((sub) => sub.userId === userId); if (!exists) { subscriptions.push({ userId, subscription }); } res.status(200).json({ message: '구독 저장 완료' }); } else { res.status(405).end(); } }

pages/api/unsubscribe.js (구독 취소)

javascript
복사편집
import { subscriptions } from '../../lib/db'; export default function handler(req, res) { if (req.method === 'POST') { const { userId } = req.body; const index = subscriptions.findIndex((s) => s.userId === userId); if (index !== -1) { subscriptions.splice(index, 1); return res.status(200).json({ message: '구독 취소 완료' }); } return res.status(404).json({ message: '구독 정보 없음' }); } res.status(405).end(); }

 


components/PushToggle.js (사용자가 알림 수신 여부를 설정하는 UI)

 
'use client'; import { useEffect, useState } from 'react'; export default function PushToggle({ userId }) { const [subscribed, setSubscribed] = useState(false); useEffect(() => { // 초기 상태 확인은 생략 가능 (구독 여부 저장 시 서버 연동) }, []); const subscribe = async () => { const registration = await navigator.serviceWorker.register('/sw.js'); const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY, }); await fetch('/api/subscribe', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId, subscription }), }); setSubscribed(true); }; const unsubscribe = async () => { const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.getSubscription(); if (subscription) { await subscription.unsubscribe(); await fetch('/api/unsubscribe', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId }), }); setSubscribed(false); } }; return ( <div> <p>알림 수신 상태: {subscribed ? 'ON' : 'OFF'}</p> <button onClick={subscribed ? unsubscribe : subscribe}> {subscribed ? '알림 끄기' : '알림 받기'} </button> </div> ); }

app/page.js

import PushToggle from '../components/PushToggle'; export default function Home() { return ( <div> <h1>사용자 맞춤 Web Push 설정</h1> <PushToggle userId="user_123" /> </div> ); }