Webhook-обробники NestJS ламаються непомітно. Глобальний ValidationPipe видаляє поля до guard, а стандартний JSON-парсинг знищує підписані байти. Локальне тестування має підтвердити rawBody: true, signature guards і валідацію на маршруті перед вставкою URL тунnelю в Stripe або GitHub.
Увімкнути raw body при bootstrap
Передайте rawBody: true при створенні додатку Nest, щоб Express зберіг нетронутий buffer:
async function bootstrap() {
const app = await NestFactory.create(AppModule, { rawBody: true });
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
await app.listen(3000);
}
Без цього прапора req.rawBody undefined і кожна HMAC-п перевірка падає.
@Body() vs req.rawBody для підписів
Ніколи не перевіряйте підпис через @Body() — Nest уже розпарсив об'єкт. Читайте buffer з raw-body middleware:
@Post('stripe')
@UseGuards(StripeSignatureGuard)
handleStripe(@Req() req: RawBodyRequest) {
const payload = req.rawBody;
const event = JSON.parse(payload.toString('utf8'));
this.events.process(event);
return { received: true };
}
Парсіть JSON лише після guard. Порядок: guard, потім десеріалізація.
Signature guard до ефектів ValidationPipe
Інкапсулюйте перевірку провайдера в guard з читанням заголовків і constant-time порівнянням:
@Injectable()
export class StripeSignatureGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const req = context.switchToHttp().getRequest>();
const sig = req.headers['stripe-signature'] as string;
return verify(req.rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET);
}
}
Застосовуйте guard через @UseGuards лише на webhook-маршруті.
Уникайте пастки глобального ValidationPipe
Глобальний ValidationPipe з transform: true може змінювати типи до контролера. Webhook-маршрути потребують rawBody + ручного JSON.parse після перевірки.
Локальне тестування nest start + PortPreview
- Запуск:
npm run start:devабоnest start --watchна порту 3000. - Відкрийте:
npx portpreview 3000. - Зареєструйте URL тунnelю + шлях webhook.
- Надішліть тестові доставки.
- Повторіть дублікати event ID — див. патерни повторів.
Типові пастки
ValidationPipe до перевірки підпису
Якщо валідація йде першою, Nest може трансформувати body і залишити rawBody порожнім. Guards мають працювати на raw buffer.
Порядок глобального JSON middleware
Express json() до raw-body споживає stream. Зберігайте rawBody: true при створенні factory.
Повільні handler і повтори
Швидко повертайте 200 після перевірки, ставте важку роботу в чергу, дедуплікуйте за event ID.
Далі
Основи — у основах тунелювання localhost та практичному локальному налагодженні вебхуків. Механіка підписів — у посібнику з перевірки підпису. Обробники без дублікатів — у патернах повторів та ідемпотентності. почніть PortPreview безкоштовно.
