javascript 如何使用NestJS将纯文本作为请求主体传递?

ctzwtxfj  于 2023-03-06  发布在  Java
关注(0)|答案(8)|浏览(179)

我的NestJS应用程序中的一个控制器方法应该将纯文本作为其主体,但是每当我尝试发出请求时,参数都被接收为空对象。这是可能的吗?或者我将不得不创建某种DTO来传递单个字符串?
示例:

@Post()
  myFunction(@Body() id: string) {
    // do something here
  }
oprakyz7

oprakyz71#

我看到这个问题是相当老,但它是列在谷歌第一,所以我想在这里添加答案。
如果你不想添加body-parser中间件(例如,你只想在单控制器方法中使用纯文本),你可以使用raw-body(它已经存在于你的node_modules中),如下所示:

import * as rawbody from 'raw-body';
import { Controller, Post, Body, Req } from '@nestjs/common';

@Controller('/')
export class IndexController {

  @Post()
  async index(@Body() data, @Req() req) {

    // we have to check req.readable because of raw-body issue #57
    // https://github.com/stream-utils/raw-body/issues/57
    if (req.readable) {
      // body is ignored by NestJS -> get raw body from request
      const raw = await rawbody(req);
      const text = raw.toString().trim();
      console.log('body:', text);

    } else {
      // body is parsed by NestJS
      console.log('data:', data);
    }

    // ...
  }

}

你也可以创建新的参数装饰器

import * as rawbody from 'raw-body';
import { createParamDecorator, HttpException, HttpStatus } from '@nestjs/common';

export const PlainBody = createParamDecorator(async (data, req) => {
  if (req.readable) {
    return (await rawbody(req)).toString().trim();
  }
  throw new HttpException('Body aint text/plain', HttpStatus.INTERNAL_SERVER_ERROR);
});

把它当作

@Post()
async index(@PlainBody() text: string) {
  // ...
  • (我没有检查装饰器代码,写在这里的评论)*
wqsoz72f

wqsoz72f2#

添加@yumaa的上述帖子
下面是NestJS v7.0.8中的装饰器:

import { createParamDecorator, ExecutionContext, BadRequestException } from '@nestjs/common';
import * as rawBody from "raw-body";

export const PlainBody = createParamDecorator(async (_, context: ExecutionContext) => {
    const req = context.switchToHttp().getRequest<import("express").Request>();
    if (!req.readable) { throw new BadRequestException("Invalid body"); }

    const body = (await rawBody(req)).toString("utf8").trim();
    return body;
})
yk9xbfzb

yk9xbfzb3#

发布请求的语义由指示内容类型的标头确定。请尝试确保请求标头的类型为“text/plain”,并查看此帮助的。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST

holgip5t

holgip5t4#

Nest与纯文本不兼容,您必须将bodyparser传递给Express应用。请尝试以下操作:

import * as bodyParser from 'body-parser';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(bodyparser({ ...options })) // for plain/text bodies
  await app.listen(3000)
}
bootstrap();

其中***选项***是从https://www.npmjs.com/package/body-parser创建的

pgx2nnw8

pgx2nnw85#

  • 老问题,但以上没有一个为我工作,但以下没有:*

上面的装饰器或控制器方法对我不起作用,因为请求主体缓冲区总是已经被读取。
我可以使用下面的中间件让它工作。(注意,在我的例子中,我需要验证一个Xero webhook,所以这个例子是针对这个问题的)
cache-raw-body-on-request.ts:

import { json } from 'body-parser';
import * as cloneBuffer from 'clone-buffer';

export const cachedRawBodyRequestKey = 'rawBodyBuffer';

/**
 * Clones the request buffer and stores it on the request object for reading later 
 */
export const cacheRawBodyOnRequest = json({
  verify: (req: any, res, buf, encoding) => {

    // only clone the buffer if we're receiving a Xero webhook request
    if (req.headers['x-xero-signature'] && Buffer.isBuffer(buf)) {
      req[cachedRawBodyRequestKey] = cloneBuffer(buf);
    }
    return true;
  },
});

main.ts:

app.use(cacheRawBodyOnRequest);

控制器:

const textBody = req[cachedRawBodyRequestKey].toString('utf-8');
gwo2fgha

gwo2fgha6#

下面是我对NestJS处理器中原始(文本)主体的看法:
1.使用preserveRawBodyInRequest配置应用程序,如JSDoc示例所示
1.在处理程序中使用RawBody装饰器来检索原始(文本)正文
raw-request.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,
      },
    ),
  );
}
py49o6xq

py49o6xq7#

如果您希望避免额外的第三方依赖项,您还可以使用built-in nodejs方法:

function readPost(req: IncomingMessage) {
  return new Promise<string>((resolve, reject) => {
    let body = '';
    req.on('data', (data: string) => (body += data));
    req.on('error', (error: unknown) => reject(error));
    req.on('end', () => resolve(body));
  });
}

用法:

import { Post, Req } from '@nestjs/common';
import { IncomingMessage } from 'http';
...
@Post()
myFunction(@Req() req: IncomingMessage) {
  const bodyStr = await readPost(req);
  console.log('request body:', bodyStr);
}
aydmsdu9

aydmsdu98#

只需动态地在NestJS中注册一个文本解析器。
您可以使用常见问题部分(https://docs.nestjs.com/faq/raw-body#raw-body)中介绍的rawBody: true选项。但是,请注意,默认情况下,仅注册 * jsonParser * 和 * urlencodedParser *。如果您希望注册其他解析器,则需要显式注册。
示例:
main.ts:

import { NestFactory } from '@nestjs/core';
import type { NestExpressApplication } from '@nestjs/platform-express';

const app = await NestFactory.create<NestExpressApplication>(module, {
  rawBody: true
});

app.useBodyParser('text')

my.controller.ts:

import { Controller, Post, RawBodyRequest, Req } from '@nestjs/common';
import { Request } from 'express';

@Post()
async post(@Req() req: RawBodyRequest<Request>) {
  console.log(req.rawBody?.toString('utf-8') ?? '')
}

相关问题