Все статьи
Как тестировать SendGrid Event Webhook на localhost
SendGridemail webhookssignature verificationlocalhost

Как тестировать SendGrid Event Webhook на localhost

Чтобы протестировать SendGrid Event Webhook на локальном хосте, запустите свой обработчик локально, обнажив его порт npx portpreview PORTВведите конечную точку HTTPS в качестве URL-адреса сообщения SendGrid и проверьте каждый запрос с помощью открытого ключа Signed Event Webhook перед обработкой его событий.

Что посылает SendGrid Event Webhook

Event Webhook сообщает, что происходит после того, как SendGrid принимает сообщение. Мероприятия по доставке включают processed, delivered, deferred, bounceи droppedМероприятия по вовлечению включают open, clickСпам-отчеты и изменения подписки. Точные поля варьируются в зависимости от типа события, поэтому маршрут в первую очередь event и рассматривать факультативные поля как факультативные.

Орган запроса - это JSON. массивНе обязательно один объект. SendGrid может поместить несколько событий в один POST. Руководитель, который предполагает req.body.event Он будет молча пропускать партию. Официальный Event Webhook ссылка документирует названия и поля мероприятий, в том числе sg_event_id и sg_message_id.

Используйте события как факты, а не команды. Например, событие delivered может обновить статус сообщения, в то время как клик может добавить запись взаимодействия. Избегайте того, чтобы обработчик кликов перезаписывал более позднее состояние отмены подписки просто потому, что запросы поступили не по порядку.

1.Создание локальной конечной точки

Этот пример Express намеренно применяет парсер сырого тела только к маршруту SendGrid. Проверка подписи зависит от точных байтов SendGrid; анализ и пересериализация JSON может изменить эти байты.

import express from 'express';
import { EventWebhook, EventWebhookHeader } from '@sendgrid/eventwebhook';

const app = express();
const verifier = new EventWebhook();
const publicKey = verifier.convertPublicKeyToECDSA(
  process.env.SENDGRID_WEBHOOK_PUBLIC_KEY,
);

app.post(
  '/webhooks/sendgrid',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    const signature = req.get(EventWebhookHeader.SIGNATURE());
    const timestamp = req.get(EventWebhookHeader.TIMESTAMP());

    if (!signature || !timestamp || !verifier.verifySignature(
      publicKey,
      req.body,
      signature,
      timestamp,
    )) {
      return res.status(403).send('invalid signature');
    }

    let events;
    try {
      events = JSON.parse(req.body.toString('utf8'));
    } catch {
      return res.status(400).send('invalid JSON');
    }
    if (!Array.isArray(events)) {
      return res.status(400).send('expected an event array');
    }

    await enqueueNewEvents(events);
    return res.sendStatus(204);
  },
);

app.use(express.json());
app.listen(3000);

Установите официального помощника с npm install @sendgrid/eventwebhookМаунт Глобал express.json() после этого маршрута или явно исключить этот путь. То же правило применяется в Next.js, Fastify, NestJS, бессерверных функциях и шлюзах API: сохраняйте исходный корпус в виде струнного или байтового буфера до тех пор, пока проверка не увенчается успехом. Официальный SendGrid Репозиторий узлов имеет соответствие Подписанный Event Webhook пример.

2. Дайте SendGrid URL HTTPS

Продолжайте работу приложения, затем откройте второй терминал:

npx portpreview 3000

PortPreview печатает общедоступное HTTPS-происхождение. Если это https://example.portpreview.devПолный URL сообщения:

https://example.portpreview.dev/webhooks/sendgrid

Путь должен точно соответствовать маршруту. Держите туннель живым во время тестирования. Туннель перенаправляет трафик; он не заменяет локальный сервер, поэтому сбои соединения обычно означают, что приложение остановлено, прослушивание на другом порту или связано таким образом, что туннель не может достичь.

3. Настройка Event Webhook в SendGrid

  1. В SendGrid UI, открытый Настройки > Настройки почты.
  2. Настройки Webhook, открытые Событие Webhooks и выбрать Создать новый webook.
  3. Включите его, добавьте URL PortPreview в качестве URL-адреса Post и выберите только те действия, которые нужны вашему приложению.
  4. В соответствии с функциями безопасности, включить Обсуждение Event Webhook.
  5. Сохраните веб-хук, повторно откройте его настройки, скопируйте сгенерированный открытый ключ проверки и сохраните его как SENDGRID_WEBHOOK_PUBLIC_KEY.
  6. Использовать Проверьте свою интеграциюЗатем отправьте реальное сообщение, чтобы использовать типы событий, которые имеют значение.

SendGrid Текущий руководство по установке Тест отправляет примеры событий, а не данные из реальной почты. Сохранение перед тестированием проверки подписи: пара ключей генерируется при сохранении конфигурации Signed Event Webhook.

Как работает SendGrid подписанная проверка webhook

Signed Event Webhook использует ECDSA. SendGrid сохраняет закрытый ключ и отображает соответствующий открытый ключ проверки для вас. Каждая поставка включает в себя X-Twilio-Email-Event-Webhook-Signature и X-Twilio-Email-Event-Webhook-TimestampПроверка охватывает временную метку, сцепленную с необработанными байтами полезной нагрузки и хэшом SHA-256; подпись кодируется Base64. Официальный помощник обрабатывает конверсию с открытым ключом, декодирование подписи, хеширование и проверку ECDSA.

Это асимметричная проверка: отображаемое значение является открытым ключом, а не секретом HMAC. Не запускайте полезную нагрузку через JSON.stringify(), обрезать белое пространство, добавить новую линию или проверить один элемент массива за раз. Сначала проверьте полные байты запроса, затем проанализируйте массив. Смотреть SendGrid документация о характеристиках безопасности Для алгоритма и заголовков.

Действительная подпись устанавливает, что подписанные байты исходили от владельца закрытого ключа SendGrid и не были изменены. Он не делает обработку событий идемпотентной, не разрешает произвольные действия и не доказывает, что событие является новым. Это отдельный контроль.

Сделать пакетную обработку идемпотентной

SendGrid повторы неудачных ПОСТ, и сети могут потерять успешный ответ. Таким образом, дублирование доставки является нормальным. Используйте каждое событие sg_event_id как основной ключ дедупликации с уникальным ограничением базы данных. Если ваш продукт объединяет несколько учетных записей или сред SendGrid, пробел имен и ключ поставщика и учетной записи или среды.

async function enqueueNewEvents(events) {
  for (const event of events) {
    await db.transaction(async (tx) => {
      const inserted = await tx.webhookReceipts.insertIfAbsent({
        provider: 'sendgrid',
        eventId: event.sg_event_id,
        receivedAt: new Date(),
      });
      if (!inserted) return;

      await tx.jobs.enqueue({
        type: 'process-sendgrid-event',
        payload: event,
      });
    });
  }
}

Вставка квитанции и прочная очередь должны быть соединены. Возврат 2xx после партии является длительным accepted. Если одно событие терпит неудачу после совершения других, ответ non-2xx может привести к возвращению всего запроса; дедупликация позволяет следующей попытке пропустить события уже accepted и продолжить безопасно. Не используйте в памяти Set в производстве, потому что перезапуск стирает его, и несколько экземпляров не разделяют его. Чем шире webhook retry и руководство по импотенции Покрывает прочные узоры.

Понимать повторы перед выбором кодов состояния

Согласно документации SendGrid Event Webhook, ответ 2xx знаменует успех POST. Ответ non-2xx вызывает повторные попытки с увеличением интервалов в течение 24 часов после события; это окно для каждого нового неудачного события. Это поведение означает, что постоянный отказ подписи может также генерировать повторяющиеся попытки, в то время как возвращение 2xx для события, которое вы никогда не хранили, теряет его.

  • 2xx: Полная партия была аутентифицирована и надежно accepted, или каждое событие уже известно.
  • 4xx: непроверенный или непроверенный вход. Зарегистрируйтесь только для безопасной диагностики; ожидайтеОтправитьGridОбщее поведение не-2xx.
  • 5xx: временная база данных, очередь или отказ приложения, которые должны быть исправлены.

Сохраняйте путь запроса коротким: проверяйте, проверяйте внешнюю форму, атомарно дублируйте и выполните очередь, а затем отвечайте. Выполняйте обновления аналитики электронной почты, синхронизацию CRM и уведомления у сотрудников.

Устранение неполадок локальные SendGrid webhooks

Подпись всегда недействительна

Наиболее распространенной причиной является промежуточное ПО JSON, потребляющее тело перед проверкой. Подтвердите, что проверяющий получает оригинал Buffer, включая любое ведущее или заднее белое пространство. Затем проверьте, что открытый ключ относится к этой точной конфигурации Event Webhook и что оба заголовка Twilio достигают приложения без изменений. Перезапустить локальный процесс после изменения окружающей среды.

Тестовая интеграция проходит успешно, но реальных событий не происходит.

Убедитесь, что веб-хук включен и что выбраны желаемые действия. Открытия требуют открытого отслеживания, а клики требуют отслеживания кликов. Также помните, что тестовый запрос содержит примеры; используйте фактическую отправку для проверки производственных полей и секвенирования.

Конечная точка возвращает 404 или 502

Для 404 сравните сконфигурированный путь с /webhooks/sendgridДля ошибок шлюза убедитесь, что локальное приложение работает на том же порту, который передан PortPreview. Если запросы поступают, но возвращаются 500, проверьте местные журналы и временно сведите обработчика к проверке плюс длительный захват.

События дублируются или выходят из строя

Это реальность системы доставки, а не доказательство того, что туннель дублировал трафик. дублировать sg_event_idПо возможности делайте переходы состояний монотонными и храните время события отдельно от времени приема. Используйте локальный webhook отладка рабочего процесса Изолировать транспортные, аутентификационные и бизнес-логические сбои.

Контрольный список безопасности для местного и производственного использования

  • Используйте HTTPS и проверьте каждую подпись, прежде чем анализировать или регистрировать детали событий.
  • Держите открытый ключ проверки в конфигурации, чтобы он мог быть обновлен чисто при изменении ключа веб-хука.
  • Примите только POST, ограничьте размер запроса, подтвердите, что парсинговое значение является массивом, и разрешите обрабатывать только имена событий.
  • Не помещайте PII в категории SendGrid или уникальные аргументы; ссылка SendGrid явно предупреждает, что эти поля хранятся и не рассматриваются как PII.
  • Не разоблачайте сеанс администратора, отладку консоли или несвязанные локальные маршруты через одно и то же временное происхождение.
  • Не регистрируйте адреса получателей, полезные нагрузки, подписи или значения окружающей среды, если это не требуется и не отредактировано надлежащим образом.
  • Замените временный туннель URL на стабильную конечную точку HTTPS после тестирования и отключите устаревшие конфигурации веб-хуков.

SendGrid также может использовать OAuth 2.0 для Event Webhook безопасности, либо отдельно, либо вместе с подписями. Если ваше развертывание требует контроля жизненного цикла токена-носителя, следуйте официальному руководству по безопасности, а не изобретайте обмен токенами. Проверка подписи остается ценной, потому что она связывает точные временные метки и байты полезной нагрузки.

Готовый к производству приемочный тест

  1. Отправьте подписанный тестовый запрос и подтвердите ответ 2xx.
  2. Измените один байт полезной нагрузки и подтвердите 403 без записи базы данных.
  3. Повторите идентичный действительный запрос и не подтвердите дублирование работы или деловых действий.
  4. Отправьте объект JSON вместо массива и подтвердите управляемый 400.
  5. Кратко остановите базу данных, подтвердите 5xx, восстановите ее и проверьте, что повторная запись accepted один раз.
  6. Отправьте настоящее электронное письмо и подтвердите, что выбранные события доставки и участия следуют тем же путем.

Как только эти проверки пройдут, переместите конечную точку на производство без изменения логики проверки и идемпотентности. Для более глубоких режимов криптографического сбоя прочитайте Руководство по проверке подписи web-cook.

Часто задаваемые вопросы

Может ли SendGrid отправить Event Webhook в локальный хост?
Не напрямую. Запустите обработчик локально, начните `npx portpreview PORT` и настройте сгенерированный общедоступный URL HTTPS плюс путь вашего веб-хука как URL-адрес поста SendGrid.
Как проверить SendGrid подписанный Event Webhook?
Прочитайте заголовки X-Twilio-Email-Event-Webhook-Signature и X-Twilio-Email-Event-Webhook-Timestamp, сохраните полный необработанный орган запроса и проверьте их с помощью открытого ключа с помощью официального помощника SendGrid Event Webhook.
почемуОтправитьGridПроверка webhook не удалась после анализа JSON
Подпись ECDSA охватывает временную метку плюс точные байты полезной нагрузки. Парсинг и ресериализация JSON могут изменять белое пространство или форматирование, поэтому проверка должна происходить против исходного буфера или строки перед парсингом JSON.
Неудалось ли SendGrid повторить Event Webhook?
Да. SendGrid документы, увеличивающие интервалы повторных попыток для ответов non-2xx в течение 24 часов после каждого события. Возвращение 2xx только после того, как партия будет аутентифицирована и долговечна accepted, и размножение с sg_event_id.