{"id":19506321,"url":"https://github.com/thenorthmemory/wechatpay-axios-plugin","last_synced_at":"2025-05-15T14:08:31.325Z","repository":{"id":38845664,"uuid":"271732101","full_name":"TheNorthMemory/wechatpay-axios-plugin","owner":"TheNorthMemory","description":"微信支付 WeChatPay OpenAPI v2\u0026v3' SDK，以命令行方式与接口交互，play the openapi requests over command line","archived":false,"fork":false,"pushed_at":"2025-05-08T10:51:21.000Z","size":567,"stargazers_count":263,"open_issues_count":2,"forks_count":40,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-15T14:08:27.461Z","etag":null,"topics":["aes-128-cbc","aes-256-ecb","aes-256-gcm","axios-ecosystem","chainable-openapi","multipart-formdata","pkcs7padding","rsa-oaep","wechatpay","wechatpay-apiv2","wechatpay-apiv3"],"latest_commit_sha":null,"homepage":"https://wechatpay.js.org/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheNorthMemory.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"custom":["https://thenorthmemory.github.io/donate.png"]}},"created_at":"2020-06-12T07:04:36.000Z","updated_at":"2025-05-15T12:43:56.000Z","dependencies_parsed_at":"2024-04-28T07:23:58.013Z","dependency_job_id":"22b8d110-25a9-4a70-96b4-cd88587298d1","html_url":"https://github.com/TheNorthMemory/wechatpay-axios-plugin","commit_stats":{"total_commits":358,"total_committers":6,"mean_commits":"59.666666666666664","dds":0.03631284916201116,"last_synced_commit":"6a162676c8ad01b98fc0c20ffe57dac5bad3136d"},"previous_names":[],"tags_count":67,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNorthMemory%2Fwechatpay-axios-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNorthMemory%2Fwechatpay-axios-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNorthMemory%2Fwechatpay-axios-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNorthMemory%2Fwechatpay-axios-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheNorthMemory","download_url":"https://codeload.github.com/TheNorthMemory/wechatpay-axios-plugin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254355335,"owners_count":22057354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes-128-cbc","aes-256-ecb","aes-256-gcm","axios-ecosystem","chainable-openapi","multipart-formdata","pkcs7padding","rsa-oaep","wechatpay","wechatpay-apiv2","wechatpay-apiv3"],"created_at":"2024-11-10T22:36:40.064Z","updated_at":"2025-05-15T14:08:31.263Z","avatar_url":"https://github.com/TheNorthMemory.png","language":"JavaScript","funding_links":["https://thenorthmemory.github.io/donate.png"],"categories":[],"sub_categories":[],"readme":"# 微信支付 OpenAPI SDK\n\nPromise based and chained WeChatPay OpenAPI SDK for NodeJS\n\n[![GitHub actions](https://github.com/TheNorthMemory/wechatpay-axios-plugin/workflows/npm%20test/badge.svg)](https://github.com/TheNorthMemory/wechatpay-axios-plugin/actions)\n[![GitHub release](https://img.shields.io/npm/v/wechatpay-axios-plugin)](https://github.com/TheNorthMemory/wechatpay-axios-plugin/releases)\n[![Vulnerabilities](https://snyk.io/advisor/npm-package/wechatpay-axios-plugin/badge.svg)](https://snyk.io/advisor/npm-package/wechatpay-axios-plugin)\n[![types](https://img.shields.io/badge/types-included-blue)](https://www.npmjs.com/package/wechatpay-axios-plugin)\n[![Node](https://img.shields.io/node/v/wechatpay-axios-plugin)](https://www.npmjs.com/package/wechatpay-axios-plugin)\n[![NPM downloads per month](https://img.shields.io/npm/dm/wechatpay-axios-plugin)](https://www.npmjs.com/package/wechatpay-axios-plugin)\n[![NPM license](https://img.shields.io/npm/l/wechatpay-axios-plugin)](https://www.npmjs.com/package/wechatpay-axios-plugin)\n\n## 系统要求\n\nNodeJs \u003e= 12\n\n## 安装\n\n`$ npm install wechatpay-axios-plugin`\n\n## [初始化](https://wechatpay.js.org/guide/getting-started#init)\n\n```js\nconst { Wechatpay } = require('wechatpay-axios-plugin');\nconst { readFileSync } = require('fs');\n\n// 商户号，支持「普通商户/特约商户」或「服务商商户」\nconst merchantId = '190000****';\n\n// 「商户API证书」的「证书序列号」\nconst merchantCertificateSerial = '3775B6A45ACD588826D15E583A95F5DD********';\n\n// 「商户API私钥」`file://`协议的本地文件绝对路径\nconst merchantPrivateKeyFilePath = 'file:///path/to/merchant/apiclient_key.pem';\n\n// APIv3 的「平台证书」接入模式 {{{\n// 「平台证书」的「证书序列号」\n// 可以从「平台证书」文件解析，也可以在 商户平台 -\u003e 账户中心 -\u003e API安全 查询到\n// const platformCertificateSerial = '7132D72A03E93CDDF8C03BBD1F37EEDF********';\n\n// 「平台证书」`file://`协议的本地文件绝对路径\n// 「平台证书」文件可由内置的CLI工具下载到\n// const platformCertificateFilePath = 'file:///path/to/wechatpay/certificate.pem';\n// }}}\n\n// APIv3 的「微信支付公钥」接入模式 {{{\n// 「微信支付公钥」`file://`协议的本地文件绝对路径\n// 需要在 商户平台 -\u003e 账户中心 -\u003e API安全 下载\nconst platformPublicKeyFilePath = 'file:///path/to/wechatpay/publickey.pem';\n\n// 「微信支付公钥」的「微信支付公钥ID」\n// 需要在 商户平台 -\u003e 账户中心 -\u003e API安全 查询\nconst platformPublicKeyId = 'PUB_KEY_ID_01142321349124100000000000********';\n// }}}\n\n// 构造一个 APIv2 \u0026 APIv3 客户端实例\nconst wxpay = new Wechatpay({\n  mchid: merchantId,\n  serial: merchantCertificateSerial,\n  privateKey: merchantPrivateKeyFilePath,\n  // 根据商户号所能接入的APIv3模式(微信支付公钥/平台证书)按需配置certs对象内容\n  certs: {\n    // 「平台证书」 接入模式时，则填 platformCertificate* 配置项及配置行，多平台证书时配多行\n    // [platformCertificateSerial]: platformCertificateFilePath,\n    // 「微信支付公钥」 接入模式时，则填 platformPublicKey* 配置项及配置行，当前新商户只此模式\n    [platformPublicKeyId]: platformPublicKeyFilePath,\n  },\n  // APIv2(密钥32字节)\n  secret: 'your_merchant_secret_key_string',\n  // 部分接口要求使用「商户API证书」的场景，需要额外配置如下{cert,key}或{pfx,passphrase}参数\n  merchant: {\n    cert: readFileSync('/path/to/merchant/apiclient_cert.pem'),\n    key: readFileSync(merchantPrivateKeyFilePath.slice(7)),\n    // 或者配置如下`passphrase`及`pfx`配置项\n    // passphrase: 'your_merchant_id',\n    // **注**: Node17.1开始使用OpenSSL3,老的p12文件需要额外格式转换\n    // pfx: readFileSync('/your/merchant/cert/apiclient_cert.p12'),\n  },\n});\n```\n\n初始化字典说明如下：\n\n- `mchid` 为你的商户号，一般是10字节纯数字\n- `serial` 为你的商户证书序列号，一般是40字节字符串\n- `privateKey` 为你的商户API私钥，一般是通过官方证书生成工具生成的文件名是`apiclient_key.pem`文件，支持纯字符串或者文件流`buffer`格式\n- `certs{[serial_number]:string}` 为`key/value`键值对，键为平台证书序列号/微信支付公钥ID，值为平台证书/微信支付公钥pem格式的纯字符串或者文件流`buffer`格式\n- `secret` 为APIv2版的`密钥`，商户平台上设置的32字节字符串\n- `merchant.cert` 为你的商户证书,一般是文件名为`apiclient_cert.pem`文件，支持纯字符串或者文件流`buffer`格式\n- `merchant.key` 为你的商户API私钥，一般是通过官方证书生成工具生成的文件名是`apiclient_key.pem`文件，支持纯字符串或者文件流`buffer`格式\n- `merchant.passphrase` 一般为你的商户号\n- `merchant.pfx` 为你的商户`PKCS12`格式的证书，文件名一般为`apiclient_cert.p12`，支持二进制文件流`buffer`格式(**注**: Node17.1开始使用OpenSSL3,老的p12文件需要额外格式转换)\n\n**注：** APIv2\u0026APIv3以及Axios初始参数，均融合在一个型参上。\n\n## APIv3\n\n### [Native下单](https://wechatpay.js.org/openapi/v3/pay/transactions/native)\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nwxpay.v3.pay.transactions.native\n  .post({\n    mchid: '1900006XXX',\n    out_trade_no: 'native12177525012014070332333',\n    appid: 'wxdace645e0bc2cXXX',\n    description: 'Image形象店-深圳腾大-QQ公仔',\n    notify_url: 'https://weixin.qq.com/',\n    amount: {\n      total: 1,\n      currency: 'CNY'\n    },\n  })\n  .then(({data: {code_url}}) =\u003e console.info(code_url))\n  .catch(({response: {\n    status,\n    statusText,\n    data\n  } }) =\u003e console.error(status, statusText, data))\n```\n\u003c/details\u003e\n\n### [查询订单](https://wechatpay.js.org/openapi/v3/pay/transactions/id/{transaction_id})\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\n// _placeholder_ 语法糖会转换成 '{placeholder}' 格式\nwxpay.v3.pay.transactions.id._transaction_id_\n  .get({\n    params: {\n      mchid: '1230000109'\n    },\n    //当商户订单号有大写字符时，只能这样参数化传递\n    transaction_id: '1217752501201407033233368018'\n  })\n  .then(({data}) =\u003e console.info(data))\n  .catch(({response: {\n    status,\n    statusText,\n    data\n  } }) =\u003e console.error(status, statusText, data))\n```\n\u003c/details\u003e\n\n### [关闭订单](https://wechatpay.js.org/openapi/v3/pay/transactions/out-trade-no/{out_trade_no}/close)\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\n// $placeholder$ 语法糖会转换成 '{placeholder}' 格式\nwxpay.v3.pay.transactions.outTradeNo.$out_trade_no$.close\n  .post({\n    mchid: '1230000109'\n  }, {\n    //当商户订单号有大写字符时，只能这样参数化传递\n    out_trade_no: 'P1217752501201407033233368018'\n  })\n  .then(({status, statusText}) =\u003e console.info(status, statusText))\n  .catch(({response: {\n    status,\n    statusText,\n    data\n  } }) =\u003e console.error(status, statusText, data))\n```\n\u003c/details\u003e\n\n### [发起退款](https://wechatpay.js.org/openapi/v3/refund/domestic/refunds)\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\n\n;(async () =\u003e {\n  try {\n    const res = await wxpay.v3.refund.domestic.refunds.post({\n      transaction_id: '1217752501201407033233368018',\n      out_refund_no: '1217752501201407033233368018',\n      reason: '商品已售完',\n      notify_url: 'https://weixin.qq.com',\n      funds_account: 'AVAILABLE',\n      amount: {\n        refund: 888,\n        from: [{\n          account: 'AVAILABLE',\n          amount: 444,\n        }],\n        total: 888,\n        currency: 'CNY'\n      },\n    });\n  } catch({response: {status, statusText, data}}) {\n    console.error(status, statusText, data)\n  }\n})()\n```\n\u003c/details\u003e\n\n**更多示例代码访问[这里](https://wechatpay.js.org/openapi/)**\n\n## APIv2\n\n### [现金红包](https://wechatpay.js.org/openapi/v2/mmpaymkttransfers/sendredpack)\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nwxpay.v2.mmpaymkttransfers.sendredpack.post({\n  nonce_str: Formatter.nonce(), // 自v0.9.0起可以无需声明\n  mch_billno: '10000098201411111234567890',\n  mch_id: '10000098',\n  wxappid: 'wx8888888888888888',\n  send_name: '鹅企支付',\n  re_openid: 'oxTWIuGaIt6gTKsQRLau2M0yL16E',\n  total_amount: '1000',\n  total_num: '1',\n  wishing: 'HAPPY BIRTHDAY',\n  client_ip: '192.168.0.1',\n  act_name: '回馈活动',\n  remark: '会员回馈活动',\n  scene_id: 'PRODUCT_4',\n})\n.then(res =\u003e console.info(res.data))\n.catch(({response: {status, statusText, data}}) =\u003e console.error(status, statusText, data))\n```\n\u003c/details\u003e\n\n### [企业付款到银行卡-获取RSA公钥](https://wechatpay.js.org/openapi/v2/risk/getpublickey)\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Rsa} = require('wechatpay-axios-plugin')\n\nwxpay.v2.risk.getpublickey.post({\n  mch_id: '1900000109',\n  sign_type: Hash.ALGO_MD5,\n  nonce_str: Formatter.nonce(), // 自v0.9.0起可以无需声明\n}, {\n  baseURL: 'https://fraud.mch.weixin.qq.com/',\n  // 声明请求是私有ssl协议，对应加载初始化的 merchant{key,cert} 参数\n  security: true,\n})\n.then(res =\u003e {\n  const b64 = res.data.pub_key.trim().split(/\\r?\\n/).slice(1, -1).join('')\n  console.info(Rsa.fromPkcs1(b64, Rsa.KEY_TYPE_PUBLIC))\n})\n.catch(({response: {status, statusText, data}}) =\u003e console.error(status, statusText, data))\n```\n\u003c/details\u003e\n\n**更多示例代码访问[这里](https://wechatpay.js.org/openapi/)**\n\n## 企业微信\n\n企业微信的企业支付，数据请求包需要额外的签名，仅需做如下简单扩展适配，即可支持；以下签名注入函数所需的两个参数`agentId` `agentSecret`来自企业微信工作台，以下为示例值。\n\n```js\nconst {Hash} = require('wechatpay-axios-plugin')\nconst agentId = '0' // 企业微信应用ID，0是企微内置的特殊应用\nconst agentSecret = Hash.keyObjectFrom('from_wework_agent_special_string') // 自v0.9.0可用\n```\n\n### 企业红包-注入签名规则\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Hash,Formatter} = require('wechatpay-axios-plugin')\n\nwxpay.client.v2.defaults.transformRequest.unshift(function workwxredpack(data) {\n  const {act_name, mch_billno, mch_id, nonce_str, re_openid, total_amount, wxappid} = data\n\n  if (!(act_name \u0026\u0026 mch_billno \u0026\u0026 mch_id \u0026\u0026 nonce_str \u0026\u0026 re_openid \u0026\u0026 total_amount \u0026\u0026 wxappid)) {\n    return data\n  }\n\n  data.workwx_sign = Hash.md5(\n    Formatter.queryStringLike(Formatter.ksort({\n      act_name, mch_billno, mch_id, nonce_str, re_openid, total_amount, wxappid\n    })), agentSecret, agentId\n  ).toUpperCase()\n\n  return data\n})\n```\n\u003c/details\u003e\n\n### 发放企业红包\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nwxpay.v2.mmpaymkttransfers.sendworkwxredpack.post({\n  mch_billno: '123456',\n  wxappid: 'wx8888888888888888',\n  sender_name: 'XX活动',\n  sender_header_media_id: '1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0',\n  re_openid: 'oxTWIuGaIt6gTKsQRLau2M0yL16E',\n  total_amount: '1000',\n  wishing: '感谢您参加猜灯谜活动，祝您元宵节快乐！',\n  act_name: '猜灯谜抢红包活动',\n  remark: '猜越多得越多，快来抢！',\n  mch_id: '1900000109',\n  nonce_str: Formatter.nonce(), // 需要显式声明\n}, {\n  // 声明请求是私有ssl协议，对应加载初始化的 merchant{key,cert} 参数\n  security: true,\n})\n.then(res =\u003e console.info(res.data))\n.catch(console.error)\n```\n\u003c/details\u003e\n\n### 向员工付款-注入签名规则\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Hash,Formatter} = require('wechatpay-axios-plugin')\nwxpay.client.v2.defaults.transformRequest.unshift(function wwsptrans2pocket(data) {\n  const {amount, appid, desc, mch_id, nonce_str, openid, partner_trade_no, ww_msg_type} = data\n\n  if (!(amount \u0026\u0026 appid \u0026\u0026 desc \u0026\u0026 mch_id \u0026\u0026 nonce_str \u0026\u0026 openid \u0026\u0026 partner_trade_no \u0026\u0026 ww_msg_type)) {\n    return data\n  }\n\n  data.workwx_sign = Hash.md5(\n    Formatter.queryStringLike(Formatter.ksort({\n      amount, appid, desc, mch_id, nonce_str, openid, partner_trade_no, ww_msg_type\n    })), agentSecret, agentId\n  ).toUpperCase()\n\n  return data\n})\n```\n\u003c/details\u003e\n\n### 向员工付款\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nwxpay.v2.mmpaymkttransfers.promotion.paywwsptrans2pocket.post({\n  appid: 'wxe062425f740c8888',\n  device_info: '013467007045764',\n  partner_trade_no: '100000982017072019616',\n  openid: 'ohO4Gt7wVPxIT1A9GjFaMYMiZY1s',\n  check_name: 'NO_CHECK',\n  re_user_name: '张三',\n  amount: '100',\n  desc: '六月出差报销费用',\n  spbill_create_ip: '10.2.3.10',\n  ww_msg_type: 'NORMAL_MSG',\n  act_name: '示例项目',\n  mch_id: '1900000109',\n  nonce_str: Formatter.nonce(), // 需要显式声明\n}, {\n  // 声明请求是私有ssl协议，对应加载初始化的 merchant{key,cert} 参数\n  security: true,\n})\n.then(res =\u003e console.info(res.data))\n.catch(console.error)\n```\n\u003c/details\u003e\n\n## 自定义打印日志\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\n// APIv2 日志\nwxpay.client.v2.defaults.transformRequest.push(data =\u003e (console.log(data), data))\nwxpay.client.v2.defaults.transformResponse.unshift(data =\u003e (console.log(data), data))\n// APIv3 日志\nwxpay.client.v3.defaults.transformRequest.push((data, headers) =\u003e (console.log(data, headers), data))\nwxpay.client.v3.defaults.transformResponse.unshift((data, headers) =\u003e (console.log(data, headers), data))\n```\n\u003c/details\u003e\n\n## XML形式通知应答\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Transformer} = require('wechatpay-axios-plugin')\nconst xml = Transformer.toXml({\n  return_code: 'SUCCESS',\n  return_msg: 'OK',\n})\n\nconsole.info(xml)\n```\n\u003c/details\u003e\n\n## aes-256-ecb/pcks7padding\n\n### 解密\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Aes: {AesEcb}, Transformer, Hash} = require('wechatpay-axios-plugin')\nconst v2Secret = Hash.keyObjectFrom('exposed_your_key_here_have_risks') // 自v0.9.0可用\nconst xml = '\u003cxml\u003e' + ... '\u003c/xml\u003e'\nconst obj = Transformer.toObject(xml)\nconst res = AesEcb.decrypt(obj.req_info, Hash.md5(v2Secret/*自v0.9.2开始支持*/))\nobj.req_info = Transformer.toObject(res)\nconsole.info(obj)\n```\n\u003c/details\u003e\n\n### 加密\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst obj = Transformer.toObject(xml)\nconst ciphertext = AesEcb.encrypt(obj.req_info, Hash.md5(v2Secret/*自v0.9.2开始支持*/))\nconsole.assert(\n  obj.req_info === ciphertext,\n  `The notify hash digest should be matched the local one`\n)\n```\n\u003c/details\u003e\n\n## APIv2数据签名\n\n### JSAPI\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Hash, Formatter} = require('wechatpay-axios-plugin')\nconst v2Secret = Hash.keyObjectFrom('exposed_your_key_here_have_risks') // 自v0.9.0可用\nconst params = {\n  appId: 'wx8888888888888888',\n  timeStamp: `${Formatter.timestamp()}`,\n  nonceStr: Formatter.nonce(),\n  package: 'prepay_id=wx201410272009395522657a690389285100',\n  signType: Hash.ALGO_HMAC_SHA256,\n}\nparams.paySign = Hash.sign(params.signType, params, v2Secret)\n\nconsole.info(params)\n```\n\u003c/details\u003e\n\n### APP\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Hash, Formatter} = require('wechatpay-axios-plugin')\nconst v2Secret = Hash.keyObjectFrom('exposed_your_key_here_have_risks') // 自v0.9.0可用\nconst params = {\n  appid: 'wx8888888888888888',\n  partnerid: '1900000109',\n  prepayid: 'WX1217752501201407033233368018',\n  package: 'Sign=WXPay',\n  timestamp: `${Formatter.timestamp()}`,\n  noncestr: Formatter.nonce(),\n}\nparams.sign = Hash.sign(Hash.ALGO_MD5, params, v2Secret)\n\nconsole.info(params)\n```\n\u003c/details\u003e\n\n## APIv3数据签名\n\n### JSAPI\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Rsa, Formatter} = require('wechatpay-axios-plugin')\nconst merchantPrivateKeyInstance = Rsa.from('file:///your/merchant/priviate_key.pem') // 自v0.9.0可用\n\nconst params = {\n  appId: 'wx8888888888888888',\n  timeStamp: `${Formatter.timestamp()}`,\n  nonceStr: Formatter.nonce(),\n  package: 'prepay_id=wx201410272009395522657a690389285100',\n  signType: 'RSA',\n}\nparams.paySign = Rsa.sign(Formatter.joinedByLineFeed(\n  params.appId, params.timeStamp, params.nonceStr, params.package\n), merchantPrivateKeyInstance)\n\nconsole.info(params)\n```\n\u003c/details\u003e\n\n### 商家券-小程序发券v2版签名规则\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Hash, Formatter} = require('wechatpay-axios-plugin')\nconst v2Secret = Hash.keyObjectFrom('exposed_your_key_here_have_risks') // 自v0.9.0可用\n\n// flat the miniprogram data transferring structure for sign\nconst busiFavorFlat = ({send_coupon_merchant, send_coupon_params = []} = {}) =\u003e {\n  return {\n    send_coupon_merchant,\n    ...send_coupon_params.reduce((des, row, idx) =\u003e (\n      Object.keys(row).map(one =\u003e des[`${one}${idx}`] = row[one]), des\n    ), {}),\n  }\n}\n\n// the miniprogram data transferring structure\nconst busiFavor = {\n  send_coupon_params: [\n    {out_request_no:'1234567',stock_id:'abc123'},\n    {out_request_no:'7654321',stock_id:'321cba'},\n  ],\n  send_coupon_merchant: '10016226'\n}\n\nbusiFavor.sign = Hash.sign(Hash.ALGO_HMAC_SHA256, busiFavorFlat(busiFavor), v2Secret)\n\nconsole.info(busiFavor)\n```\n\u003c/details\u003e\n\n### 商家券-H5发券v2版签名规则\n\n\u003cdetails\u003e\u003csummary\u003e示例代码\u003c/summary\u003e\n\n```js\nconst {Hash, Formatter} = require('wechatpay-axios-plugin')\nconst v2Secret = Hash.keyObjectFrom('exposed_your_key_here_have_risks') // 自v0.9.0可用\nconst params = {\n  stock_id: '12111100000001',\n  out_request_no: '20191204550002',\n  send_coupon_merchant: '10016226',\n  open_id: 'oVvBvwEurkeUJpBzX90-6MfCHbec',\n  coupon_code: '75345199',\n}\nparams.sign = Hash.sign(Hash.ALGO_HMAC_SHA256, params, v2Secret)\n\nconsole.info(params)\n```\n\u003c/details\u003e\n\n## 常见问题\n\nQ: `APIv3`上请求参数敏感信息如何加密？返回参数敏感信息如何解密？\n\n\u003e 接口区分国内版还是国际版，国内版的`RSA`填充方案是`RSA_PKCS1_OAEP_PADDING`，方法如下：\n\u003e\n\u003e 加密: `Rsa.encrypt('原始信息', Rsa.from(platformPublicKeyFilePath, Rsa.KEY_TYPE_PUBLIC))`\n\u003e\n\u003e 解密: `Rsa.decrypt('密文base64', Rsa.from(merchantPrivateKeyFilePath, Rsa.KEY_TYPE_PRIVATE))`\n\u003e\n\u003e 国际版`RSA`填充方案是`RSA_PKCS1_PADDING`，本类库放弃支持此种`加/解密`填充方案，同时`node18.19.0`也是最后一版默认支持`加密`的版本(延展阅读见[CVE-2023-46809](https://nodejs.org/en/blog/vulnerability/february-2024-security-releases)及[这里](https://github.com/wechatpay-apiv3/wechatpay-php/issues/133))，如需使用，请自行寻替代方案。\n\n\nQ: 如何安全地在应用内使用`APIv2`及`APIv3`对称密钥?\n\n\u003e `v0.9.0`提供了统一的对称密钥加载函数 `Hash.keyObjectFrom(thing: BinaryLike): KeyObject`，建议应用升级至`v0.9.2`使用此函数进行统一对称密钥管理;\n\nQ: 如何加载`RSA`公/私钥和`X509`证书公钥？\n\n\u003e `v0.9.0`提供了统一的加载函数 `Rsa.from(thing: KeyLike, type: 'public'|'private'): KeyObject`\n\u003e\n\u003e - `Rsa.from(thing, type)` 支持从文件/字符串/字节流加载公/私钥和证书，特别地，支持`file://`, `private.pkcs8://`, `private.pkcs1://`, `public.pkcs1://`, `public.spki://` 协议的公/私钥字符串；\n\u003e - `Rsa.fromPkcs1`是个语法糖，支持加载 `PKCS#1` 格式的公/私钥，入参是 `base64` 字符串;\n\u003e - `Rsa.fromPkcs8`是个语法糖，支持加载 `PKCS#8` 格式的私钥，入参是 `base64` 字符串;\n\u003e - `Rsa.fromSpki`是个语法糖，支持加载 `SPKI` 格式的公钥，入参是 `base64` 字符串;\n\nQ: APIv3消息通知，`AES-256-GCM`加密字段，应该如何解密？\n\n\u003e 官方文档有介绍，APIv3平台证书及消息通知关键信息均使用`AesGcm`加解密，依赖`APIv3密钥`，商户侧解密可参考`bin/cli/cert.js`证书下载工具，例如：\n\u003e ```js\n\u003e AesGcm.decrypt(ciphertext, secret, nonce, aad);\n\u003e ```\n\nQ: 敏感信息或者幂等操作要求额外头信息上送时，应该如何构建请求参数？\n\n\u003e `DELETE`/`GET`请求的第一个参数，`POST`/`PUT`/`PATCH`请求的第二个参数，是 [AxiosRequestConfig](https://github.com/axios/axios) 对象，可以按需上送额外头参数，例如：\n\u003e\n\u003e 可参考 [这里](https://wechatpay.js.org/openapi/v3/applyment4sub/applyment/) 或 [这里](https://wechatpay.js.org/openapi/v3/marketing/partnerships/build) 的实现\n\n## 单元测试\n\n`npm install \u0026\u0026 npm test`\n\n## 技术交流\n\n如果遇到困难或建议可以 提ISSUE 或 加群，交流技术，分享经验。\n\nQQ群: **684379275**\n\n## 链接\n\n如果你觉得这个`library`不错，你可以扫如下`赞赏码`以资鼓励作者，[博客](https://thenorthmemory.github.io/)更有部分\"实战\"内容，也可能对你的开发对接有所帮助。\n\n\u003cimg src=\"https://thenorthmemory.github.io/donate.png\" /\u003e\n\n\n- [参与贡献](CONTRIBUTING.md)\n- [贡献者公约](CODE_OF_CONDUCT.md)\n- [变更历史](CHANGELOG.md)\n\n## 许可证\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthenorthmemory%2Fwechatpay-axios-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthenorthmemory%2Fwechatpay-axios-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthenorthmemory%2Fwechatpay-axios-plugin/lists"}