데브포일 홈
DEV MODE - 실서버 영향 없음 📦 배포 관리
웹훅 시스템 구축
+350 XP
LEVEL 76 QUEST

웹훅 시스템 구축

웹훅 시스템 구축 — DevFoil 바이브코딩 Stage 16, Lv.76

웹훅이란 무엇인가?
이벤트가 발생하면 알려주는 시스템
API를 호출해서 데이터를 가져오는 것은 "내가 물어보는 것"(Polling)입니다. 반면 웹훅은 "이벤트가 발생하면 자동으로 알려주는 것"(Push)입니다.

결제 완료, 새 주문, 코드 커밋, 메시지 수신 등 이벤트가 발생하는 즉시 지정된 URL로 HTTP POST 요청을 보내는 방식입니다.

폴링 vs 웹훅 비교:
  • 폴링: "새 주문 있어?" → "없어" → 5초 후 → "새 주문 있어?" → "있어!" (비효율적)
  • 웹훅: 새 주문 발생 → 즉시 "새 주문이야!" HTTP POST 전송 (효율적)
항목폴링(Polling)웹훅(Webhook)
방식주기적으로 요청이벤트 시 자동 전송
지연폴링 간격만큼거의 실시간
서버 부하높음 (불필요한 요청)낮음 (필요할 때만)
구현 난이도쉬움보통
안정성높음 (클라이언트 제어)재시도 로직 필요
웹훅 수신 서버 구축
안전한 웹훅 엔드포인트 만들기
웹훅 수신 서버는 보안, 검증, 빠른 응답 세 가지를 반드시 갖춰야 합니다. 먼저 즉시 200을 응답한 뒤, 실제 처리는 비동기로 수행합니다.
// AI 프롬프트: "보안이 내장된 웹훅 수신 서버 만들어줘"
const express = require('express');
const crypto = require('crypto');
const app = express();

// raw body 보존 (서명 검증용)
app.use('/webhooks', express.json({
  verify: (req, res, buf) => {
    req.rawBody = buf;
  }
}));

// 웹훅 서명 검증 함수
function verifySignature(req, secret) {
  const signature = req.headers['x-webhook-signature'];
  if (!signature) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(req.rawBody)
    .digest('hex');

  // 타이밍 공격 방지 (일정한 시간에 비교)
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(`sha256=${expected}`)
  );
}

// 웹훅 수신 엔드포인트
app.post('/webhooks/:source', async (req, res) => {
  const source = req.params.source;
  const secret = process.env[`WEBHOOK_SECRET_${source.toUpperCase()}`];

  // 1. 서명 검증
  if (!verifySignature(req, secret)) {
    console.error(`서명 검증 실패: ${source}`);
    return res.status(401).json({ error: '서명이 유효하지 않습니다' });
  }

  // 2. 즉시 200 응답 (타임아웃 방지)
  res.status(200).json({ received: true });

  // 3. 비동기 처리
  try {
    await processWebhook(source, req.body);
  } catch (error) {
    console.error(`웹훅 처리 실패: ${source}`, error);
    await logFailedWebhook(source, req.body, error);
  }
});
🔒
여기까지는 미리보기입니다
웹훅 시스템 구축
무료 가입하면 이어서 볼 수 있고, 강의를 완료할 때마다 XP와 레벨이 쌓입니다.
Google로 3초 만에 시작 →🧵 Threads로 시작무료 공개 강의 둘러보기 (Lv.1~3)