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

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

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

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

  1. <xml>
  2. <ToUserName><![CDATA[toUser]]></ToUserName>
  3. <FromUserName><![CDATA[fromUser]]></FromUserName>
  4. <CreateTime>1348831860</CreateTime>
  5. <MsgType><![CDATA[text]]></MsgType>
  6. <Content><![CDATA[this is a test]]></Content>
  7. <MsgId>1234567890123456</MsgId>
  8. </xml>

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

比如被动回复用户消息:

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

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

  1. <xml>
  2. <ToUserName><![CDATA[toUser]]></ToUserName>
  3. <FromUserName><![CDATA[fromUser]]></FromUserName>
  4. <CreateTime>12345678</CreateTime>
  5. <MsgType><![CDATA[text]]></MsgType>
  6. <Content><![CDATA[你好]]></Content>
  7. </xml>

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

创建示例项目

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

  1. $ nest n xml-handling

XML 数据的接收

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

安装依赖

  1. $ yarn add body-parser body-parser-xml

启用 body-parser 中间件

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

src/main.ts

  1. import { NestFactory } from '@nestjs/core';
  2. import { AppModule } from './app.module';
  3.  
  4. const bodyParser = require('body-parser');
  5. require('body-parser-xml')(bodyParser);
  6.  
  7. async function bootstrap() {
  8. const app = await NestFactory.create(AppModule);
  9.  
  10. app.use(
  11. bodyParser.xml({
  12. xmlParseOptions: {
  13. explicitArray: false, // 始终返回数组。默认情况下只有数组元素数量大于 1 是才返回数组。
  14. },
  15. }),
  16. );
  17.  
  18. await app.listen(3000);
  19. }
  20. bootstrap();

接收并处理 XML 数据

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

src/app.controller.ts

  1. import { Body, Controller, Logger, Post } from '@nestjs/common';
  2. import { inspect } from 'util';
  3.  
  4. /**
  5. * 微信回调给开发者的消息
  6. */
  7. interface IWxMessageXmlData {
  8. /** 开发者微信号 e.g. `gh_019087f88815`*/
  9. ToUserName: string;
  10. /** 发送方帐号(一个OpenID)e.g.: `o5w5awUl***5pIJKY`*/
  11. FromUserName: string;
  12. /** 消息创建时间 (整型)e.g.`1595855711` */
  13. CreateTime: string;
  14. /** 消息类型,此处为 `event` */
  15. MsgType: string;
  16. /** 事件类型,subscribe(订阅)、unsubscribe(取消订阅) */
  17. Event: 'subscribe' | 'unsubscribe';
  18. /** 事件KEY值,目前无用 */
  19. EventKey: string;
  20. }
  21.  
  22. @Controller()
  23. export class AppController {
  24. @Post('wxhandler')
  25. async wxhandler(@Body('xml') xmlData: IWxMessageXmlData) {
  26. Logger.log(`xml data got: ${inspect(xmlData)}`);
  27. return '';
  28. }
  29. }

测试:

  1. $ curl --location --request POST 'localhost:3000/wxhandler' \
  2. --header 'Content-Type: application/xml' \
  3. --data-raw '<xml>
  4. <ToUserName><![CDATA[toUser]]></ToUserName>
  5. <FromUserName><![CDATA[fromUser]]></FromUserName>
  6. <CreateTime>1348831860</CreateTime>
  7. <MsgType><![CDATA[text]]></MsgType>
  8. <Content><![CDATA[this is a test]]></Content>
  9. <MsgId>1234567890123456</MsgId>
  10. </xml>'

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

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

XML 数据的返回

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

安装依赖

  1. $ yarn add xmlbuilder2

使用 xmlbuilder2 创建 XML 数据

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

src/app.controller.ts

  1. import { Body, Controller, Logger, Post } from '@nestjs/common';
  2. import { inspect } from 'util';
  3. + import { create } from 'xmlbuilder2';
  4.  
  5. @Controller()
  6. export class AppController {
  7. @Post('wxhandler')
  8. async wxhandler(@Body('xml') xmlData: IWxMessageXmlData) {
  9. Logger.log(`xml data got:\n ${inspect(xmlData)}\n`);
  10. + const res = create({
  11. + xml: {
  12. + ToUserName: 'openid_xxx', // 接收方帐号(收到的OpenID)
  13. + FromUserName: 'openod_yyy', // 开发者微信号
  14. + CreateTime: new Date().getTime(), // 消息创建时间 (整型)
  15. + MsgType: 'text',
  16. + Content: 'some text',
  17. + },
  18. + }).end({ prettyPrint: true });
  19. return res;
  20. }
  21. }

测试并查看返回:

  1. $ curl --location --request POST 'localhost:3000/wxhandler' \
  2. --header 'Content-Type: application/xml' \
  3. --data-raw '<xml>
  4. <ToUserName><![CDATA[toUser]]></ToUserName>
  5. <FromUserName><![CDATA[fromUser]]></FromUserName>
  6. <CreateTime>1348831860</CreateTime>
  7. <MsgType><![CDATA[text]]></MsgType>
  8. <Content><![CDATA[this is a test]]></Content>
  9. <MsgId>1234567890123456</MsgId>
  10. </xml>'
  11. <?xml version="1.0"?>
  12. <xml>
  13. <ToUserName>openid_xxx</ToUserName>
  14. <FromUserName>openod_yyy</FromUserName>
  15. <CreateTime>1603109187287</CreateTime>
  16. <MsgType>text</MsgType>
  17. <Content>some text</Content>
  18. </xml>⏎

示例代码

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

相关资源

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

Nest 中处理 XML 类型的请求与响应的更多相关文章

  1. Spring Boot 2.x基础教程:如何扩展XML格式的请求和响应

    在之前的所有Spring Boot教程中,我们都只提到和用到了针对HTML和JSON格式的请求与响应处理.那么对于XML格式的请求要如何快速的在Controller中包装成对象,以及如何以XML的格式 ...

  2. 知方可补不足~sqlserver中对xml类型字段的操作

    回到目录 在sqlserver中有很多种数据类型,而XML数据类型是比较新奇怪的一种格式,我们平常接触的可能比较少,用的也少,而在某些场合,使用XML类型可能会使我们的开发变简单,下面就是一种情况: ...

  3. T-SQL——关于XML类型

    目录 0. 将结果集转化为XML格式 1. 列值拼接为字符串 2. 字符串转换为列值 3. 一些说明 参考 志铭-2021年10月23日 10:43:21 0. 将结果集转化为XML格式 测试数据 I ...

  4. HTTP协议简介详解 HTTP协议发展 原理 请求方法 响应状态码 请求头 请求首部 java模拟浏览器客户端服务端

    协议简介 协议,自然语言里面就是契约,也是双方或者多方经过协商达成的一致意见; 契约也即类似于合同,自然有甲方123...,乙方123...,哪些能做,哪些不能做; 通信协议,也即是双方通过网络通信必 ...

  5. Java Servlet (1) —— Filter过滤请求与响应

    Java Servlet (1) -- Filter过滤请求与响应 版本: Java EE 6 参考来源: Oracle:The Java EE 6 Tutorial: Filtering Reque ...

  6. Fiddler之模拟响应、修改请求或响应数据(断点)

    在测试过程中,有时候需要修改请求或响应数据,或者直接模拟服务器响应,此时可以使用fiddler进行此类操作.可以使用断点功能完成. 一.修改请求数据 在发起请求后,需要修改请求的数据时,可以设置请求前 ...

  7. Spring Boot中如何扩展XML请求和响应的支持

    在之前的所有Spring Boot教程中,我们都只提到和用到了针对HTML和JSON格式的请求与响应处理.那么对于XML格式的请求要如何快速的在Controller中包装成对象,以及如何以XML的格式 ...

  8. Spring Boot中扩展XML请求和响应的支持

    在Spring Boot中,我们大多时候都只提到和用到了针对HTML和JSON格式的请求与响应处理.那么对于XML格式的请求要如何快速的在Controller中包装成对象,以及如何以XML的格式返回一 ...

  9. struts.xml中的结果类型与视图

    实际上在Struts2框架中,一个完整的结果视图配置文件应该是: ? 1 2 3 4 5 <action name="Action名称" class="Action ...

随机推荐

  1. iOS图片预览、放大缩小

    思路 图片预览,优先考虑基础控件UIImageView.UIButton 图片预览中可能需设置不同的mode,优先考虑UIImageView typedef NS_ENUM(NSInteger, UI ...

  2. 微信小程序:报错fail webview count limit exceed

    报错: 分析原因: 先从列表页面跳转到详细页面时,使用了Navigator标签,open-type默认使用的navigate,跳转时会保留当前页, <navigator class=" ...

  3. SpringCloud(一):微服务架构概述

    1-1.  系统进化理论概述 在系统架构与设计的实践中,经历了两个阶段,一个阶段是早些年常见的集中式系统,一个阶段是近年来流行的分布式系统: 集中式系统: 集中式系统也叫单体应用,就是把所有的程序.功 ...

  4. Go语言学习之路-11-方法与接口

    目录 编程方式 go语言对象方法 自定义类型和方法 接收器: 方法作用的目标(类型和方法的绑定) go面向对象总结 方法的继承 go语言接口 为什么要用接口 接口的定义 接口的作用总结 接口的嵌套 空 ...

  5. 大话Spark(7)-源码之Master主备切换

    Master作为Spark Standalone模式中的核心,如果Master出现异常,则整个集群的运行情况和资源都无法进行管理,整个集群将处于无法工作的状态. Spark在设计的时候考虑到了这种情况 ...

  6. 洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树

    洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树 题目描述 方伯伯正在做他的 \(Oj\) .现在他在处理 \(Oj\) 上的用户排名问题. \(Oj\) 上注册了 \(n\) 个用户 ...

  7. java 给时间增加时间得到一个新的时间(日期)

    SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd") LocalDate expirationDate String exp ...

  8. Java实现解压缩文件和文件夹

    一 前言 项目开发中,总会遇到解压缩文件的时候.比如,用户下载多个文件时,服务端可以将多个文件压缩成一个文件(例如xx.zip或xx.rar).用户上传资料时,允许上传压缩文件,服务端进行解压读取每一 ...

  9. Elasticsearch 单字符串多字段查询

    前言 有些时候,我们搜索的时候,只会提供一个输入框,但是会查询相关的多个字段,典型的如Google搜索,我们该如何用 Elasticsearch 如何实现呢? 实例 从单字符串查询的实例说起 创建测试 ...

  10. FTP操作/Passive/Active控制

    1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using System.IO; 5 using ...