0x01 背景
笔者最近在使用 Nest.js 开发服务端程序,遇到了一些需要处理 XML 的场景,搜遍了网络上发现没有比较优雅的方式,于是摸索后将过程整理出来。
0x02 研究
Google 搜索 nest handle xml
的第一个结果是一篇中文文章:
Nest 中处理 XML 类型的请求与响应
但是照猫画虎了一番,发现 TS 总是报错,可能是 body-parser-xml 实现得不算很优雅,而且对 TS 支持得不够好,就放弃了。
Nest.js 底层框架默认是 Express,搜索得知默认会使用 body-parser
来处理请求,但是不支持,所以第一步首先要修改支持 application/xml
的 **Content-Type,**配合 Nest 的 middleware,我们可以封装一层,只针对单个 module 来使用。
同时对比了一下 XML 的处理模块,发现 fast-xml-parser ⭐️⭐️最多,所以决定使用它来进行 XML 和 JSON 间的相互转换。
0x03 编码
好,上代码~,首先我们创建一个 middleware,使用如下命令:
代码语言:javascript复制nest g middleware xml
Nest CLI 会生成 xml.middleware.ts
,编写如下代码:
import { Injectable, NestMiddleware } from '@nestjs/common';
import * as bodyParser from 'body-parser';
const bodyParserMiddleware = bodyParser.text({
limit: '1024kb',
type: 'application/xml',
});
@Injectable()
export class XMLMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
bodyParserMiddleware(req, res, next);
}
}
以上代码只是封装了一层 body-parser
,使之可以处理 XML 请求。
然后在 app.module.ts
中添加这个 middleware:
import { XMLMiddleware } from './common/xml.middleware';
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(XMLMiddleware).forRoutes({
path: 'wework/*',
method: RequestMethod.POST,
});
}
}
由于笔者是开发企业微信的回调服务,所以这里只针对 wework
开头的接口应用。
随后就可以在 controller 中使用 @Body
接收到 XML 字符串了。如:
import { Body, Controller, Post, Logger } from '@nestjs/common';
import * as xmlParser from 'fast-xml-parser';
@Controller('wework')
export class UsersController {
private logger = new Logger(UsersController.name);
@Post('callback')
respond(@Body() body): string {
if (xmlParser.validate(body) !== true) {
return 'xml invalid';
}
this.logger.log('from controller', body);
const parsed = xmlParser.parse(body);
return this.weworkService.respond(parsed.xml);
}
}
然后使用 fast-xml-parser
即可将 XML 字符串转换成 JSON 串了~
这样虽然也能使用了,但是解析 XML 的操作还是要写在业务代码中,就如上述代码中的
代码语言:javascript复制const parsed = xmlParser.parse(body);
那么有没有更优雅的方式呢?
答案是有的,这就要用到 Nest.js 中的 Custom Decorator 了
0x04 优化
首先新建一个 decorator,使用如下指令:
代码语言:javascript复制nest g decorator xml
nest 会生成一个 xml.decorator.ts
文件,编写如下代码:
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import * as xmlParser from 'fast-xml-parser';
export const XML = createParamDecorator((data: string, ctx: ExecutionContext) => {
const { body } = ctx.switchToHttp().getRequest();
if (xmlParser.validate(body) !== true) {
return 'xml invalid';
}
const { xml } = xmlParser.parse(body);
return xml;
});
这里的逻辑比较简单,就是先校验 XML,然后解析并返回。
需要注意的是
fast-xml-parser
解析后的返回值是包在xml
属性里的,所以需要解构一下。
到了使用的地方,我们只要像使用其他 Decorator 一样,在 Controller 的参数那里调用即可:
代码语言:javascript复制@Post('callback/:uuid')
@HttpCode(200)
async respond(@Param('uuid') uuid, @XML() parsed: IWeworkEncrypt) {
return this.weworkService.respond(uuid, parsed);
}
0x05 总结
到这里本篇文章主要内容就完了,整体思路比较简单,个人感觉这个框架用起来还是有一定门槛的,不过相关的生态都很完善,大部分问题都能找到解决方案~
由于是 Nest.js 新手,对里面的概念理解的不是很透彻,不过有问题可以多多交流哈~