Koa系框架(egg/cabloy)如何获取微信支付回调请求中的xml参数
发布于 5 年前 作者 zhennann 6177 次浏览 来自 分享

背景

在Koa系框架(如EggJS)中进行微信支付开发时,遇到一个问题:微信支付平台会发送一个回调请求,通知支付订单的处理结果。该请求传入的参数是xml格式,而Koa中间件koa-bodyparser对xml格式的请求参数没有做处理,这就需要我们在程序中自行处理

通用处理逻辑

网上通用的处理逻辑,都是类似如下的代码:

const bb = require('bluebird');

const xml = await bb.fromCallback(cb => {
  let data = '';
  this.ctx.req.setEncoding('utf8');
  this.ctx.req.on('data', function(chunk) {
    data += chunk;
  });
  this.ctx.req.on('end', function() {
    cb(null, data);
  });
});

分析与疑问

上面这段代码通过响应request对象的事件接收xml数据,对于微信支付这个场景简单有效,但是作为一个通用的xml处理机制,还是有所欠缺。request对象有如下事件:abortedclosedataenderror,此外,请求参数还有可能使用了压缩算法。如何对这些场景做更完整的处理呢?

借用中间件koa-bodyparser

由于Koa系框架(如EggJS)使用中间件koa-bodyparser对请求参数做预处理工作。那么最完整的处理逻辑也一定在中间件koa-bodyparser中。具体的源码这里不列出,可以参考如下链接:

通过分析中间件koa-bodyparser所引用的源码,我们就可以得到一个更简洁的xml处理代码,而且适应场景也更广,代码如下:

const raw = require('raw-body');
const inflate = require('inflation');

const xml = await raw(inflate(this.ctx.req));

CabloyJS的进一步封装

CabloyJS后端是基于EggJS定制的上层应用框架。CabloyJS通过向context对象注入一个通用的方法getPayload,那么在实际的开发场景中就更加方便了

注入方法

async getPayload(options) {
  return await raw(inflate(this.req), options);
}

实际调用

const xml = await this.ctx.getPayload();

===> 更正

@atian25 提示:直接修改中间件koa-bodyparser的配置,即可支持xml的解析。经测试通过,具体方法如下:

修改config配置

config.default.js

  config.bodyParser = {
    enableTypes: [ 'json', 'form', 'text' ],
    extendTypes: {
      text: [ 'application/xml' ],
    },
  };

直接取值

const xml = this.ctx.request.rawBody;
4 回复

不用那么复杂,bodyparser 的 extendTypes 配置下,把 xml 映射为 text,然后自己引入个 xmk 库 parse 下 rawbody 即可

@atian25 👍已更正

@zhennann CabloyJS 其实可以内置一个中间件,判断是这种类型的,自动把 ctx.request.body = xml.parse(ctx.request.rawBody) parse 下就好了,不用额外加个 getPayload,开发者体验就一致了。

@atian25 有道理。我考虑一下

回到顶部