• Nest 中处理 XML 类型的请求与响应


    公众号及小程序的微信接口是通过 xml 格式进行数据交换的。

    比如接收普通消息的接口:

    当普通微信用户向公众账号发消息时,微信服务器将 POST 消息的 XML 数据包到开发者填写的 URL 上。

    -- 微信官方文档 - 接收普通消息

    <xml>
      <ToUserName><![CDATA[toUser]]></ToUserName>
      <FromUserName><![CDATA[fromUser]]></FromUserName>
      <CreateTime>1348831860</CreateTime>
      <MsgType><![CDATA[text]]></MsgType>
      <Content><![CDATA[this is a test]]></Content>
      <MsgId>1234567890123456</MsgId>
    </xml>

    不仅微信端推送给我们的数据是 XML 类型的,我们调用微信接口,也需要传递 XML 类型的数据。

    比如被动回复用户消息:

    当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个 POST 请求,开发者可以在响应包(Get)中返回特定 XML 结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。

    -- 微信官方文档 - 被动回复用户消息

    <xml>
      <ToUserName><![CDATA[toUser]]></ToUserName>
      <FromUserName><![CDATA[fromUser]]></FromUserName>
      <CreateTime>12345678</CreateTime>
      <MsgType><![CDATA[text]]></MsgType>
      <Content><![CDATA[你好]]></Content>
    </xml>

    因此,不同于常见的 JSON,要求我们在接口中需要处理 XML 格式的数据。

    创建示例项目

    使用 Nest 的命令行工具创建一个示例项目用于后面的演示。

    $ nest n xml-handling

    XML 数据的接收

    接收和处理 XML 类型的数据,可使用 body-parser-xml

    安装依赖

    $ yarn add body-parser body-parser-xml

    启用 body-parser 中间件

    使用上面的中间件对请求传递的 XML 数据进行解析。

    src/main.ts

    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    
    const bodyParser = require('body-parser');
    require('body-parser-xml')(bodyParser);
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
    
      app.use(
        bodyParser.xml({
          xmlParseOptions: {
            explicitArray: false, // 始终返回数组。默认情况下只有数组元素数量大于 1 是才返回数组。
          },
        }),
      );
    
      await app.listen(3000);
    }
    bootstrap();

    接收并处理 XML 数据

    假设配置的是微信在收到用户消息时,调用我们的 wxhandler 接口。

    src/app.controller.ts

    import { Body, Controller, Logger, Post } from '@nestjs/common';
    import { inspect } from 'util';
    
    /**
     * 微信回调给开发者的消息
     */
    interface IWxMessageXmlData {
      /** 开发者微信号 e.g. `gh_019087f88815`*/
      ToUserName: string;
      /** 发送方帐号(一个OpenID)e.g.: `o5w5awUl***5pIJKY`*/
      FromUserName: string;
      /** 消息创建时间 (整型)e.g.`1595855711` */
      CreateTime: string;
      /** 消息类型,此处为 `event` */
      MsgType: string;
      /** 事件类型,subscribe(订阅)、unsubscribe(取消订阅) */
      Event: 'subscribe' | 'unsubscribe';
      /** 事件KEY值,目前无用 */
      EventKey: string;
    }
    
    @Controller()
    export class AppController {
      @Post('wxhandler')
      async wxhandler(@Body('xml') xmlData: IWxMessageXmlData) {
        Logger.log(`xml data got: ${inspect(xmlData)}`);
        return '';
      }
    }

    测试:

    $ curl --location --request POST 'localhost:3000/wxhandler' 
    --header 'Content-Type: application/xml' 
    --data-raw '<xml>
      <ToUserName><![CDATA[toUser]]></ToUserName>
      <FromUserName><![CDATA[fromUser]]></FromUserName>
      <CreateTime>1348831860</CreateTime>
      <MsgType><![CDATA[text]]></MsgType>
      <Content><![CDATA[this is a test]]></Content>
      <MsgId>1234567890123456</MsgId>
    </xml>'

    从打印的日志中查看解析后的 XML 数据:

    [Nest] 89424   - 10/19/2020, 7:58:00 PM   xml data got:
     { ToUserName: 'toUser',
      FromUserName: 'fromUser',
      CreateTime: '1348831860',
      MsgType: 'text',
      Content: 'this is a test',
      MsgId: '1234567890123456' }
     +3850ms

    XML 数据的返回

    让接口响应 XML 数据,需要我们在代码中先创建该类型的数据,可通过 xmlbuilder2 来进行。

    安装依赖

    $ yarn add xmlbuilder2

    使用 xmlbuilder2 创建 XML 数据

    通过上述工具进行 XML 的创建然后作为请求的响应。

    src/app.controller.ts

    import { Body, Controller, Logger, Post } from '@nestjs/common';
    import { inspect } from 'util';
    + import { create } from 'xmlbuilder2';
    
    @Controller()
    export class AppController {
      @Post('wxhandler')
      async wxhandler(@Body('xml') xmlData: IWxMessageXmlData) {
        Logger.log(`xml data got:
     ${inspect(xmlData)}
    `);
    +   const res = create({
    +     xml: {
    +       ToUserName: 'openid_xxx', //	接收方帐号(收到的OpenID)
    +       FromUserName: 'openod_yyy', //	开发者微信号
    +       CreateTime: new Date().getTime(), //	消息创建时间 (整型)
    +       MsgType: 'text',
    +       Content: 'some text',
    +     },
    +   }).end({ prettyPrint: true });
        return res;
      }
    }

    测试并查看返回:

    $ curl --location --request POST 'localhost:3000/wxhandler' 
                                   --header 'Content-Type: application/xml' 
                                   --data-raw '<xml>
                                     <ToUserName><![CDATA[toUser]]></ToUserName>
                                     <FromUserName><![CDATA[fromUser]]></FromUserName>
                                     <CreateTime>1348831860</CreateTime>
                                     <MsgType><![CDATA[text]]></MsgType>
                                     <Content><![CDATA[this is a test]]></Content>
                                     <MsgId>1234567890123456</MsgId>
                                   </xml>'
    <?xml version="1.0"?>
    <xml>
      <ToUserName>openid_xxx</ToUserName>
      <FromUserName>openod_yyy</FromUserName>
      <CreateTime>1603109187287</CreateTime>
      <MsgType>text</MsgType>
      <Content>some text</Content>
    </xml>

    示例代码

    以上代码可在这个示例仓库 wayou/xml-handling 中找到。

    相关资源

    The text was updated successfully, but these errors were encountered:

    CC BY-NC-SA 署名-非商业性使用-相同方式共享
  • 相关阅读:
    进程、线程、协程
    C++内存模型
    动态库dll与静态库lib
    virtual 虚函数表
    C++面试随笔
    alloc()、malloc()、calloc()、realloc()区别及用法
    C/C++ 面试题记录
    VC底层钩子程序在Win7/Vista下无效
    JMeter安装之后修成中文版
    明天开始 新的旅程
  • 原文地址:https://www.cnblogs.com/Wayou/p/14701671.html
Copyright © 2020-2023  润新知