thenorthmemory / wechatpay-axios-plugin Goto Github PK
View Code? Open in Web Editor NEW微信支付 WeChatPay OpenAPI v2&v3' SDK,以命令行方式与接口交互,play the openapi requests over command line
License: MIT License
微信支付 WeChatPay OpenAPI v2&v3' SDK,以命令行方式与接口交互,play the openapi requests over command line
License: MIT License
form-data 包是一款非常好的包,不过有一个 form-data/form-data#396 貌似停留好久没有解决,这个造成其在nodejs环境上有点小问题就是 Object.prototype.toString.call
不准,而直接调用实例的toString
也是有一些问题,尝试用ES6重写一遍。
目标:
stream.Readable
实现pipe功能node-request
包的 is.formData 探测class Multipart
上的迭代器写法 Iterator<Array<string|undefined, Buffer|ReadStream>>
异常
调用Apiv3,h5下单直接报AssertionError [ERR_ASSERTION]: It's allowed time offset in ± 5 minutes, the response was on undefined, your's localtime on 1624555111.
Error: error:0909006C:PEM routines:get_name:no start line
at Sign.sign (internal/crypto/sig.js:105:29)
at Function.sign (E:\work\ad\payment-applet\cloudfunctions\login\node_modules_wechatpay-axios-plugin@0.4.4@wechatpay-axios-plugin\lib\rsa.js:60:23)
at signer (E:\work\ad\payment-applet\cloudfunctions\login\node_modules_wechatpay-axios-plugin@0.4.4@wechatpay-axios-plugin\lib\interceptor.js:71:27)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
684379275
插件v3/combine-transactions/jsapi 官网/v3/pay/transactions/jsapi,这种情况请求结果未处理。插件打印{"code":"SYSTEM_ERROR","message":"系统繁忙,请稍后重试"},AssertionError [ERR_ASSERTION]: It's allowed time offset in ± 5 minutes, the response was on undefined, your's localtime on 1623291910.
如:get https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/t1689056263200?need_query_detail=true&detail_status=ALL
,其中 参数t1689056263200
应该是 T1689056263200
,导致无法查询到记录。
感谢你提供的开发库。
我在使用的过程中碰到了一个问题。
try {
const res = await wxpay.v3.pay.partner.transactions.native({
sp_appid,
sp_mchid,
sub_mchid,
description,
out_trade_no,
time_expire: new Date( (+new Date) + 33*60*1000 ), //after 33 minutes
attach,
notify_url,
amount: {
total: 1,
}
})
console.info(res.data.code_url)
} catch (error) {
console.error(error)
}
})()
按照示例可以正常调用微信支付的API。
现在我想调用另外一个接口,“特约商户进件”,https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/
try {
const result = await this.wxapi.v3.applyment4sub.applyment({});
return console.log(result);
} catch (err) {
return console.error(err)
}
这次接口调用返回404 Not Found.
通过catch 到的内容,我检查了请求的信息,如下:
config: {
url: '/v3/applyment4sub/applyment',
method: 'post',
data: '{}',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'User-Agent': 'wechatpay-axios-plugin/0.4.5 axios/0.21.1 node/14.15.4 darwin/x64',
Authorization: 'WECHATPAY2-SHA256-RSA2048 mchid="1270921201",nonce_str="KKuwhzeDvaIU6eykvDn4oYM7QZkjBVRu",signature="RXOv9YfWJBw/DjHpqQgsjzHJjkRXxIOthtXAL+J/mx0CfUnGlSwMciZagHgCAG8S5x8XR3q1B/khavW8YNPHM2n4Q/ooHc8EKFCRH+uPSN6iqIqluG5iTNd53a7h92/vk6zMKcMCH58ocJRvm/vMH/3CUUzRfpSJkCVccAVIgL3WpVGvzhBrUbTfP0PepwNselJqAXjCzC6MQgo83QrUHaHbdx8llz2Cs6v0tw8yD5faT+eaybHhPCOuc/qk9Y1ITRSSgRv6mfWUIE19LHPDDbI2hKjkzQUPbPwPNj9XK/OY0BV1NIgfxdYlK8RPX1HBquwwDiC4EKmUFr6v0/6NNA==",timestamp="1616655313",serial_no="623FFEC95EF4B583D2157DFE81E66FFA15DE67C3"',
'Content-Length': 2
},
baseURL: 'https://api.mch.weixin.qq.com',
...
看起来请求的数据没有什么异常。
我把headers里面的内容,通过postman 发起一个请求,是可以得到微信平台的应答的。
所以不知道是不是其他的问题导致的,希望能帮我看一下,谢谢。
APPID、MCHID、自己设置的32位KEY, 我看php sdk有个版本,只需要上面那3个参数即可H5
根据日志看,如果微信异步通知和用户前端主动触发订单查询,会造成程序卡死
版本:0.8.11
写如下代码:
this.wxpay.v3.transfer.batches.outBatchNo.$out_batch_no$.get({
params: {
mchid: '123456',
},
out_batch_no: params.out_batch_no,
})
得到TS提示:
Object literal may only specify known properties, and 'out_batch_no' does not exist in type 'AxiosRequestConfig<any>'.ts(2353)
比如下面这串代码:
wxpay.v3.transfer.batches.outBatchNo['1234567899900011'].details.outDetailNo['x16683940311151111X'].get();
后面的outDetailNo参数最后一位X会被正则处理成 ‘-x’;
我想在同一个服务中使用两个商户,创建两个实例后,调用前一个实例会返回如下信息(使用API v3):
{
code: 'PARAM_ERROR',
message: 'http header中的mchid与post payload中的mchid不匹配'
}
需要说明的是,注释掉后一个实例,使用前一个实例正常。安装依赖版本为:v0.8.6
不过看到老师您之前说支持多商户 #44,来请教一下
axios/lib/util
内置方法的依赖Hash.hmacSha256
, Aes.encrypt
, Aes.decrypt
AesGcm.encrypt
, AesGcm.decrypt
型参顺序user-agent
事情是这样的:微信的向用户付款到零钱的接口,目前没有v3、只有v2,文档在这里
令人吐血的是,这个接口的商户号字段名称是"mchid",而非绝大多数接口使用的"mch_id"。
因此我的代码如下:
const reqObj = {
mch_appid: wxmpAppId,
mchid: wxpayMchid,
nonce_str: nanoid(32),
partner_trade_no: dbObj._id,
openid: user.openId,
check_name: "NO_CHECK",
amount: Math.round(amount * 100),
desc: description
}
const resp = await wxpay.v2.mmpaymkttransfers.promotion.transfers.post(reqObj)
这样的代码产生如下报错:
"AssertionError [ERR_ASSERTION]: The data.mch_id(undefined) doesn't matched init one(*****)\n" +
' at signer (*****/node_modules/wechatpay-axios-plugin/lib/transformer.js:37:14)\n' +
' at transform (*****/node_modules/axios/lib/core/transformData.js:16:12)\n' +
' at Object.forEach (*****/node_modules/axios/lib/utils.js:247:10)\n' +
' at transformData (*****/node_modules/axios/lib/core/transformData.js:15:9)\n' +
' at dispatchRequest (*****/node_modules/axios/lib/core/dispatchRequest.js:30:17)\n' +
......
经过我分析,原因是:
wechatpay-axios-plugin/lib/transformer.js
Lines 34 to 38 in 4826863
我的建议是将上面第35行改为:
const { sign_type: type = 'MD5 } = data;
const mchid = data.mch_id || data.mchid;
应该就可以解决这个问题。
不知道您觉得是否可以,如果可以的话,我可以发布pull request上来。
最后,对您长期以来编写和维护这样一个很好用的库,表示衷心的感谢!
建议:
/**
* 向axios实例中注入拦截器
* @param {AxiosStatic} axios
* @param {string} mchid
* @param {string} serial
* @param {string} privateKey
* @param {string} publicCert
* @param {Object} certs
* @returns {AxiosStatic}
* @constructor
*/
const Interceptor = (axios, {...} = {}) =>
node 12
以下版本不支持import/export
微信v3验签是否有支持的方法?
Cannot find module './lib/Decorator'
const body = {
amount: {
total: 0.01,
currency: "CNY"
},
appid: appID,
description: 'app下单测试',
mch_id: mchid,
notify_url: 'https://www.xxx.com/wechatPayNotifyUrl',
out_trade_no: '20210910123456789'
};
const result = await wxpay.v3.pay.transactions.native.post(body)
console.info('[下单结果]',result)
{\"code\":\"PARAM_ERROR\",\"detail\":{\"location\":\"body\",\"value\":0.01},\"message\":\"无法将 JSON 输入源“/body/amount/total”映射到目标字段“总金额”中,此字段需要 一个合法的 64 位有符号整数\"}
建议保留微信官方的错误码返回
the response
debug info:
status: 204,
statusText: 'No Content',
headers: {
server: 'nginx',
date: 'Tue, 14 Jul 2020 08:50:03 GMT',
'content-type': 'application/json; charset=utf-8',
'content-length': '0',
connection: 'close',
'cache-control': 'no-cache, must-revalidate',
'x-content-type-options': 'nosniff',
'request-id': '3v0fd7',
'content-language': 'zh-CN',
'wechatpay-nonce': '...',
'wechatpay-signature': '...',
'wechatpay-timestamp': '...',
'wechatpay-serial': '...'
},
data: ''
wechatpay-axios-plugin/lib/interceptor.js
Line 25 in 38534fb
如果要求调用方传入了证书序列号的话,就不需要传入商户证书了
原本应该出现在then里面的回调,出现在catch里面
wxpay.v3.pay.transactions.jsapi .post(payParames) .then((res) => console.log(res,'回调成功')) .catch(({response: {status, statusText, data}}) => console.log(status, statusText, data,'回调失败'));
log打印 undefined undefined {"prepay_id":"---------"} 回调失败
初始化的时候,报
ERROR 438408 nodejs.unhandledRejectionError: Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream
这是什么原因导致的,求助,谢谢
查询优惠券详情,应该是get,不是post
命令行交互工具集
play the openapi requests over command line
lib/interceptor.js
文件,在验签的时候,特殊处理了204状态码的返回值,有缺陷(官方有可能返回201状态码)RT
wxpay.v2.mmpaymkttransfers.sendredpack.post();
AssertionError [ERR_ASSERTION]: the response's sign(undefined) doesn't matched the local calculated(483441D8A1B327CFFDED84EC3DE510B8)
at Object.verifier (D:\wwwroot\haoyunqingdaojia\xiaochenxu\cloudfunctions\user\node_modules\wechatpay-axios-plugin\lib\transformer.js:93:12)
at transform (D:\wwwroot\haoyunqingdaojia\xiaochenxu\cloudfunctions\user\node_modules\axios\lib\core\transformData.js:18:15)
at Object.forEach (D:\wwwroot\haoyunqingdaojia\xiaochenxu\cloudfunctions\user\node_modules\axios\lib\utils.js:245:10)
at Object.transformData (D:\wwwroot\haoyunqingdaojia\xiaochenxu\cloudfunctions\user\node_modules\axios\lib\core\transformData.js:17:9)
at onAdapterResolution (D:\wwwroot\haoyunqingdaojia\xiaochenxu\cloudfunctions\user\node_modules\axios\lib\core\dispatchRequest.js:57:35)
APIv2
版数据验签规则是,解析出xml后,读取对象内的 sign
字段,对返回串做key/value
排序转字符串加 Hash
验签。
xml
中无 sign
字段(然而数据是有效的),目前的实现对这种是直接返回处理;账单下载
接口返回值存在二象性
,即无账单时返回xml
,有账单时返回 csv
buffer;尝试对这两种异构接口做特殊transformResponse
处理,恢复大部分接口的强校验
返回内容功能。
Interceptor
是函数,不是类,首字母应小写secret
未使用,应当删除const Interceptor = (axios, {
mchid,
serial,
privateKey,
publicCert,
certs,
} = {
mchid: '',
serial: '',
privateKey: '',
publicCert: '',
certs: null,
}) => {
建议补充异常处理逻辑代码示例,以提醒开发者应当小心处理通信异常
”特约商户进件API“中要求
商户上送敏感信息时使用微信支付平台公钥加密,证书序列号包含在请求HTTP头部的Wechatpay-Serial,
请问可以从哪里进行这一步操作,向http header 中添加自定义的内容?
我在./lib/interceptor.js中找到的一部分代码
config.headers = {
...config.headers,
'User-Agent': utils.userAgent(),
'Content-Type': `application/json`,
Accept: `application/json`,
// @see {fmt.authorization} APIv3 `Authorization` schema
Authorization: fmt.authorization(mchid, nonce, signature, timestamp, serial),
}
直接添加字段是可以的。
config.headers = {
...config.headers,
'User-Agent': utils.userAgent(),
'Content-Type': `application/json`,
Accept: `application/json`,
// @see {fmt.authorization} APIv3 `Authorization` schema
Authorization: fmt.authorization(mchid, nonce, signature, timestamp, serial),
'wechatpay-serial': '1234567890',
}
不过我如何在应用程序中做这个添加的动作?
this.wxapi = new Wechatpay({
mchid: '1270921201',
serial: '623FFEC95EF4B583D2157DFE81E66FFA15DE88C3',
certs: {
'1C38E366EE3D40AF84E321A2B2A371B8CED57255': '-----BEGIN CERTIFICATE-----\n' + `...` + '\n-----END CERTIFICATE-----',
},
privateKey: '-----BEGIN PRIVATE KEY-----\n' + `...` + '\n-----END PRIVATE KEY-----',
});
初始化的时候提供了平台证书,是否应该自己在需要的时候在interceptor.js中自行添加?
还是有其他的配置,可以在接口调用的时候通过配置来添加?
谢谢。
const merchantPrivateKey = readFileSync('/your/home/hellowechatpay/apiclient_key.pem')
...
(async () => {
const res1 = await client.get('/v3/merchant-service/complaints', {...})
...
})()
TypeError [ERR_INVALID_ARG_TYPE]: The "key" argument must be of type string or an instance of ArrayBuffer, Buffer, TypedArray, DataView, KeyObject, or CryptoKey. Received undefined
at new NodeError (node:internal/errors:363:5)
at prepareAsymmetricKey (node:internal/crypto/keys:570:9)
at preparePublicOrPrivateKey (node:internal/crypto/keys:581:10)
at Verify.verify (node:internal/crypto/sig:217:7)
at Function.verify (/root/payapi2/node_modules/wechatpay-axios-plugin/lib/rsa.js:78:23)
at verifier (/root/payapi2/node_modules/wechatpay-axios-plugin/lib/interceptor.js:115:11)
at runMicrotasks ()
奇怪的是 有的机器没有问题,有的有问题
certs[serial]=wechatpayPublicCert
const client = wxp(instance, {
mchid: global.微信服务商Id,
serial: serial,
privateKey: merchantPrivateKey,
certs: certs
});
serial 变量是传入的参数
interceptor.js 文件第98行 有定义变量const serial = response.headers[wechatpay-serial
]
这个是不是有冲突
在113行 应该是检查返回数据的签名
certs[serial] 这个是获取不到内容的
不知道出错的原因是不是这个
The "key" argument must be of type string or an instance of Buffer, TypedArray, DataView, or KeyObject. Received undefined,
接口再浏览器上看已经返回成功了。但是代码还是报错
想弄个证书自动获取发现源码大量的静态函数,静态字段,搞哭了
这样导致实际上只有一个全局的wechatPay,其实new根本就是一个假象
我还没测试过如果系统有多个wechatpay实例 会怎么样
用例说明: “用例3:【刷卡-正常】订单金额0.03元(含0.01元代金券和0.02元免充值现金券),用户支付成功 “
使用版本: 0.7.13
刷卡支付验收用例1和2 沙箱测试成功。 用例网址
我的代码:
const express = require("express");
const app = express();
const { Wechatpay, Formatter } = require("wechatpay-axios-plugin");
const { readFileSync } = require("fs");
const mchid = "16*********";
const appid = "wx*****************";
//已更换为沙箱密钥
const sandbox_signkey = "33*************************";
const mch_id = mchid;
// 商户号
const merchantId = "16*********";
// 商户证书序列号
const merchantCertificateSerial = "17*********";
// 商户私钥
const merchantPrivateKeyFilePath = "/home/test/apiclient_key.pem";
const merchantPrivateKeyInstance = readFileSync(merchantPrivateKeyFilePath);
// 平台证书
const platformCertificateFilePath =
"/home/test/platformTools/wechat********.pem";
const platformCertificateInstance = readFileSync(platformCertificateFilePath);
// 平台证书序列号
const platformCertificateSerial = "26*********";
const wxpay = new Wechatpay({
mchid: merchantId,
serial: merchantCertificateSerial,
privateKey: merchantPrivateKeyInstance,
certs: { [platformCertificateSerial]: platformCertificateInstance },
// APIv2密钥(32字节)
secret: sandbox_signkey,
});
app.use(express.json());
app.post("/pay_test", async (req, res) => {
let authcode = req.body.paycode;
let totalfee = JSON.parse(req.body.payamount);
// 模拟一个商户订单号
let out_trade_no = `No${+new Date()}_100`;
try {
// 付款码沙箱用例:请求支付
console.log("付款码沙箱用例:请求支付");
console.log(
(
await wxpay.v2.sandboxnew.pay.micropay({
appid,
mch_id,
nonce_str: Formatter.nonce(),
out_trade_no,
body: "sandbox_goods_test",
total_fee: totalfee,
spbill_create_ip: "127.0.0.1",
auth_code: authcode,
})
).data
);
// 付款码沙箱用例:获取支付结果
console.log("付款码沙箱用例:获取支付结果");
console.log(
(
await wxpay.v2.sandboxnew.pay.orderquery({
appid,
mch_id,
nonce_str: Formatter.nonce(),
out_trade_no,
})
).data
);
} catch (error) {
console.log("以下打印回调报错:");
console.log(error);
}
res.send("remote server sandbox test done!");
});
const port = process.env.PORT || 8888;
app.listen(port, () => {
console.log("Server listening on post", port);
});
请求支付成功,获取支付结果时报错信息:
付款码沙箱用例:请求支付(成功)
{
coupon_fee: '3',
cash_fee_type: 'CNY',
nonce_str: 'k29n9z4bBZp20vIFr4TL96VLi2Hwgewm',
time_end: '202109*********',
sign: '******************',
coupon_id_0: '10000',
coupon_id_1: '10001',
coupon_fee_0: '1',
coupon_fee_1: '2',
fee_type: 'CNY',
attach: 'sandbox_attach',
device_info: 'sandbox',
out_trade_no: 'TestNo1632**********_10',
transaction_id: '************************',
openid: '****************',
trade_type: 'MICROPAY',
return_code: 'SUCCESS',
err_code_des: 'ok',
mch_id: '*******************',
settlement_total_fee: '1',
coupon_batch_id_1: '56789',
coupon_batch_id_0: '12345',
cash_fee: '0',
is_subscribe: 'Y',
return_msg: 'OK',
bank_type: 'CMC',
coupon_type_1: 'NO_CASH',
coupon_type_0: 'CASH',
total_fee: '3',
appid: '*****************',
coupon_count: '2',
result_code: 'SUCCESS',
err_code: 'SUCCESS'
}
付款码沙箱用例:获取支付结果
以下打印回调报错:
AssertionError [ERR_ASSERTION]: the response's sign(***F5477552*********) doesn't matched the local calculated(****69C84B**********)
at Object.verifier (/home/test/pay-sandbox-server-0.713/node_modules/wechatpay-axios-plugin/lib/transformer.js:93:12)
at transform (/home/test/pay-sandbox-server-0.713/node_modules/axios/lib/core/transformData.js:18:15)
at Object.forEach (/home/test/pay-sandbox-server-0.713/node_modules/axios/lib/utils.js:245:10)
at Object.transformData (/home/test/pay-sandbox-server-0.713/node_modules/axios/lib/core/transformData.js:17:9)
at onAdapterResolution (/home/test/pay-sandbox-server-0.713/node_modules/axios/lib/core/dispatchRequest.js:57:35)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async /home/test/pay-sandbox-server-0.713/index.js:77:9 {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: false,
expected: true,
operator: '=='
}
Originally posted by @qaoo8 in #35 (comment)
感谢作者的开源项目,帮了很多忙,await wxpay.v3.profitsharing.orders.post({}) ,在云函数,使用这样调用请求分账,返回{},不知问题出在哪。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.