NestJS - 在请求正文中接受多种 MIME 类型

Man*_*nny 1 xml json nestjs

我正在尝试在 HTTP API 中创建一个端点,定期从远程设备接收数据。该项目发生了技术转变,设备之前以 XML 格式报告数据,而未来的实现将转向 JSON。

我正在使用 NestJS (7.x) 和 TypeScript 编写此 API。数据将通过相同的端点 ( ) 传入POST /,并且数据格式由标头区分Content-Type

@Controller()
export class IngressController {
  constructor(private readonly ingressService: IngressService) {
  }

 /* ... */

  @Post('')
  @Header('Cache-Control', 'none')
  @HttpCode(HttpStatus.NO_CONTENT)
  public async receive(
    @Headers('Content-Type') contentType: string,
    @Req() req: any,
    @Body() body: string,
  ): Promise<InsertResponse> {
    if (IngressController.isJson(contentType)) {
      return { inserted: await this.ingressService.insertJsonString(req.body) };
    }
    if (IngressController.isXml(contentType)) {
      return { inserted: await this.ingressService.insertXmlString(req.body) };
    }
    throw new BadRequestException(contentType, 'Unsupported Content-Type');
  }

 /* ... */
}
Run Code Online (Sandbox Code Playgroud)

未来的设备将以 JSON 格式报告数据(由Content-Type: application/jsonHTTP 请求中的标头指示),而传统设备将以 XML ( Content-Type: application/xml) 格式报告数据。

它对于 JSON 来说效果非常好。然而,我的问题是req.body(或body分别)在 XML 情况下是一个空对象。我猜想 NestJS 中间件正在做一些事情并被 XML 搞糊涂了,但我没有发现任何关于允许 XML 有效负载与 JSON 并排的提示。我不介意手动解析它。

eol*_*eol 5

正如您怀疑的那样,NestJS 有一个内置的 bodyparser,它将无法解析 xml。您可以做的是插入一个自定义中间件,您可以在其中决定是将请求正文解析为 xml 还是将请求传递到下一个处理程序。

像这样的东西应该可以工作(我express-xml-bodyparser在这个例子中使用):

import {NestFactory} from '@nestjs/core';
import {AppModule} from './app.module';
import {Request} from "express";

const xmlParser = require('express-xml-bodyparser');
const xmlParserMidleware = xmlParser();

async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.use((req: Request, res: any, next: any) => {
        if (req.path.includes("/api/json-or-xml-handler") && req.header('Content-Type')?.includes('xml')) {
            return xmlParserMidleware(req, res, next);
        }
        next();
    });
    await app.listen(8020);
}

bootstrap();
Run Code Online (Sandbox Code Playgroud)

然后,在你的控制器中将body是解析后的 json 对象或 xml 的对象表示:

@Controller()
export class TestControllerController {
    @Post('/api/json-or-xml-handler')
    receive(@Body() body: any) {
        console.log(body);
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)