Landing Page GuideMở ứng dụng
Khóa 614 phútBài 7/10

Webhook

Webhook là gì, payload JSON mẫu, xác thực bằng chữ ký và secret, xử lý gửi lại, chống trùng và không lộ secret trên frontend.

Mục tiêu bài học
  • Hiểu cơ chế webhook và khác biệt với gọi API định kỳ
  • Đọc payload JSON và thiết kế endpoint nhận
  • Xác thực chữ ký, xử lý retry và chống xử lý trùng

Webhook là cách một hệ thống tự gửi thông báo tới hệ thống khác ngay khi có sự kiện, bằng một yêu cầu HTTP POST tới URL bạn cung cấp. Thay vì cứ vài phút hỏi "có lead mới chưa?", hệ thống nguồn sẽ chủ động báo "vừa có lead mới, đây là dữ liệu".

JSONFormMáy chủCRM
Sự kiện xảy ra → hệ thống nguồn gửi POST kèm chữ ký → endpoint xác thực → xử lý.
Payload JSON mẫu khi có lead mới{ "event": "lead.created", "id": "evt_01J9X", "created_at": "2026-10-19T08:30:00Z", "data": { "lead_id": "L-1024", "need": "nhan-det", "quantity": "500-1000", "utm_source": "facebook", "utm_campaign": "nhan-det-q4-2026", "consent_marketing": false } }

Xác thực: chỉ tin webhook có chữ ký đúng

  1. Hai bên dùng chung một secret, lưu ở server (ví dụ secrets của Worker), không bao giờ ở frontend.
  2. Bên gửi tính chữ ký HMAC-SHA256 của nội dung yêu cầu (thường kèm dấu thời gian) bằng secret, đặt vào header.
  3. Bên nhận tự tính lại chữ ký từ nội dung thô nhận được và so sánh. Không khớp thì trả lỗi 401 và bỏ qua.
  4. Kiểm tra dấu thời gian, từ chối yêu cầu quá cũ để chống gửi lại (replay).

Retry và chống trùng

  • Bên gửi thường gửi lại khi không nhận được phản hồi 2xx, nên cùng một sự kiện có thể đến nhiều lần
  • Lưu id sự kiện đã xử lý; nếu gặp lại id cũ thì trả 200 và bỏ qua (idempotency)
  • Trả phản hồi 2xx nhanh, việc nặng (gửi email, gọi CRM) nên đưa vào hàng đợi xử lý sau
  • Khi chính bạn gửi webhook đi: thử lại với khoảng chờ tăng dần, ghi log lần thất bại cuối cùng để xử lý tay
Không đặt secret webhook, token CRM hay khóa API trong mã JavaScript của trang, trong URL công khai hay trong kho mã công khai. Nếu lỡ lộ, đổi secret ngay. Hạn chế đưa dữ liệu cá nhân vào payload: chỉ gửi trường bên nhận thật sự cần.

Endpoint an toàn

  • Xác thực chữ ký trên nội dung thô
  • Kiểm tra dấu thời gian
  • Chống trùng bằng id sự kiện
  • Trả 2xx nhanh, xử lý nặng ở hàng đợi
  • Log có ẩn dữ liệu cá nhân

Endpoint dễ bị lợi dụng

  • Nhận mọi POST không kiểm tra
  • Secret ghi trong frontend
  • Xử lý trùng tạo lead lặp, gửi email lặp
  • Ghi log toàn bộ payload có số điện thoại
Khi thử nghiệm, dùng dữ liệu giả và môi trường thử riêng. Nhiều dịch vụ có nút "gửi thử webhook" giúp bạn kiểm tra endpoint trước khi chạy thật.

Bài tập thực hành

Thiết kế một webhook "lead mới" từ endpoint form tới CRM: viết payload JSON (chỉ trường cần thiết), header chữ ký, các bước xác thực và cách xử lý khi gửi trùng hoặc lỗi.

Gợi ý: Dùng payload mẫu trong bài và lược bỏ trường không cần. Viết quy trình nhận theo thứ tự: xác thực → chống trùng → lưu → phản hồi.

  • Payload có id sự kiện và thời gian
  • Có xác thực chữ ký bằng secret lưu ở server
  • Có cơ chế chống xử lý trùng
  • Có chiến lược retry và log khi lỗi
  • Payload không chứa dữ liệu cá nhân thừa

Làm bài & lưu ghi chú trong ứng dụng

Kiểm tra kiến thức

1. Webhook khác gọi API định kỳ ở điểm nào?
  1. Webhook chậm hơn
  2. Hệ thống nguồn chủ động gửi khi có sự kiện, không cần hỏi liên tục
  3. Webhook chỉ dùng cho email
  4. Không khác gì
Xem đáp án

B. Hệ thống nguồn chủ động gửi khi có sự kiện, không cần hỏi liên tục — Webhook đẩy dữ liệu ngay khi sự kiện xảy ra, tiết kiệm tài nguyên so với hỏi định kỳ.

2. Vì sao cần chống xử lý trùng ở endpoint webhook?
  1. Vì bên gửi có thể gửi lại cùng sự kiện khi không nhận được phản hồi
  2. Vì JSON hay bị lỗi
  3. Vì luật yêu cầu
  4. Không cần
Xem đáp án

A. Vì bên gửi có thể gửi lại cùng sự kiện khi không nhận được phản hồi — Cơ chế retry khiến một sự kiện có thể đến nhiều lần; không chống trùng sẽ tạo lead hoặc email lặp.

3. Secret dùng để ký webhook nên lưu ở đâu?
  1. Trong JavaScript của trang
  2. Trong secrets phía server
  3. Trong URL
  4. Trong thẻ meta
Xem đáp án

B. Trong secrets phía server — Mọi thứ ở frontend đều có thể bị đọc; secret phải nằm ở server.

Nguồn tham khảo chính thức