web-dev-qa-db-fra.com

Accéder au corps brut de bande Web à rayures dans Nest.js

J'ai besoin d'accéder au corps brut de la demande WebHook de la bande dans mon nid.js demande.

Après - ceci exemple, j'ai ajouté le menu ci-dessous au module ayant une méthode de contrôleur qui nécessite le corps brut.

function addRawBody(req, res, next) {
  req.setEncoding('utf8');

  let data = '';

  req.on('data', (chunk) => {
    data += chunk;
  });

  req.on('end', () => {
    req.rawBody = data;

    next();
  });
}

export class SubscriptionModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(addRawBody)
      .forRoutes('subscriptions/stripe');
  }
}

Dans le contrôleur, j'utilise @Req() req, puis req.rawBody Pour obtenir le corps brut. J'ai besoin du corps brut car le constructif de l'API de rayures l'utilise pour vérifier la demande.

Le problème est que la demande est bloquée. Il semble que le req.on ne soit pas appelé pour les données ni pour l'événement final. Donc, next() n'est pas appelé au middleware.

J'ai aussi essayé d'utiliser raw-body Comme - ici mais j'ai eu à peu près le même résultat. Dans ce cas, le req.Readable est toujours faux, alors je suis coincé là aussi.

Je suppose que c'est un problème avec Nest.js mais je ne suis pas sûr ...

10
theva

C'est mon objectif d'obtenir le corps brut (texte) du handeur de Nestjs:

  1. configurez l'application avec preserveRawBodyInRequest comme indiqué dans l'exemple JSDOC (pour limiter uniquement pour la bande Web Webhook "stripe-signature" comme en-tête de filtre)
  2. utilisez RawBody décorateur dans le gestionnaire pour récupérer le corps brut (texte)

raw-Demande.Decorator.ts:

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { NestExpressApplication } from "@nestjs/platform-express";

import { json, urlencoded } from "express";
import type { Request } from "express";
import type http from "http";

export const HTTP_REQUEST_RAW_BODY = "rawBody";

/**
 * make sure you configure the nest app with <code>preserveRawBodyInRequest</code>
 * @example
 * webhook(@RawBody() rawBody: string): Record<string, unknown> {
 *   return { received: true };
 * }
 * @see preserveRawBodyInRequest
 */
export const RawBody = createParamDecorator(
  async (data: unknown, context: ExecutionContext) => {
    const request = context
      .switchToHttp()
      .getRequest<Request>()
    ;

    if (!(HTTP_REQUEST_RAW_BODY in request)) {
      throw new Error(
        `RawBody not preserved for request in handler: ${context.getClass().name}::${context.getHandler().name}`,
      );
    }

    const rawBody = request[HTTP_REQUEST_RAW_BODY];

    return rawBody;
  },
);

/**
 * @example
 * const app = await NestFactory.create<NestExpressApplication>(
 *   AppModule,
 *   {
 *     bodyParser: false, // it is prerequisite to disable nest's default body parser
 *   },
 * );
 * preserveRawBodyInRequest(
 *   app,
 *   "signature-header",
 * );
 * @param app
 * @param ifRequestContainsHeader
 */
export function preserveRawBodyInRequest(
  app: NestExpressApplication,
  ...ifRequestContainsHeader: string[]
): void {
  const rawBodyBuffer = (
    req: http.IncomingMessage,
    res: http.ServerResponse,
    buf: Buffer,
  ): void => {
    if (
      buf?.length
      && (ifRequestContainsHeader.length === 0
        || ifRequestContainsHeader.some(filterHeader => req.headers[filterHeader])
      )
    ) {
      req[HTTP_REQUEST_RAW_BODY] = buf.toString("utf8");
    }
  };

  app.use(
    urlencoded(
      {
        verify: rawBodyBuffer,
        extended: true,
      },
    ),
  );
  app.use(
    json(
      {
        verify: rawBodyBuffer,
      },
    ),
  );
}
0
kaznovac