简介:这是一份面向C#开发者的支付对接实战资源,覆盖微信支付与支付宝支付两大主流渠道,同时兼顾Winform桌面端与H5移动网页两种使用场景。资源以C#后端接口代码与HTML前端页面组合呈现,适合需要为桌面应用或手机网页快速接入支付能力的开发者,也适合刚接触第三方支付接口的学员对照真实流程学习。压缩包体积约50.86MB,整体包含C#接口实现、HTML支付页面及相关配置文件,核心模块涵盖下单、签名、回调通知等支付环节,可在手机端打开测试链接体验H5支付页面效果。当前已有461人学习下载,具有较好的参考价值。通过这套资源,读者能获得微信/支付宝从发起支付到通知处理的完整代码思路,以及前端H5页面唤起支付的关键实现方式;代码结构清晰,便于提取改造,可帮助开发者减少前期调研时间,直接迁移到自有项目中。无论是集成到现有平台还是作为学习案例,都能节约大量排查问题的时间。
1. 微信支付和支付宝支付,C# 后端与 H5 前端到底怎么搭
给 Winform 桌面程序加微信支付或支付宝支付,最尴尬的场面往往是:业务逻辑都写完了,用户却要举起手机对着屏幕扫二维码,付完还得人工确认到账。想体验好一点,就得在手机端拉起一个 H5 收银台,点两下直接跳进微信或支付宝完成付款。CSDN(pay).zip 这套资源解决的就是这个衔接问题——C#(Winform) 负责统一下单、签名、回调验签,H5(Html) 负责收银台和支付结果页,测试链接 http://dumikj.com/pay.html 用手机浏览器打开就能看到前端效果。适合正在做收银系统、门店管理、内部订单系统,且后端是 C# 技术栈的开发者。
这套东西的价值不在代码量,而在把“桌面程序 + 手机页面 + 两个支付平台”三套体系串起来。Winform 没有 Web 项目那种天然的路由和回调入口,前端页面又要处理跨域、跳转、回跳,问题往往不是单个接口不会调,而是整条链路不知道怎么闭合。下面从选型开始,一路讲到联调和上线,尽量把参数、代码、坑一次性说清楚。
2. 支付对接前先理清三件事:H5 选型、参数模型、签名
对接支付最常见的问题不是接口不会调,而是不知道选哪种支付产品。微信支付本身就分 JSAPI、H5、Native、App 好几种,参数和拉起方式完全不同;支付宝也有手机网站支付、电脑网站支付、App 支付的区别。选型不定,后面的代码全是白写。所以这一章先把模型讲透,再给可抄的参数表和签名代码。
2.1 为什么选 H5 支付而不是扫码或 App 支付
看用户到底在哪里付钱。如果用户是在微信 App 里打开公众号网页,要用 JSAPI 支付;如果用户是用手机自带浏览器打开收银台,要用微信 H5 支付,对应 trade_type 为 MWEB;如果用户只是对着电脑屏幕扫码,Native 或扫码支付就够了。Winform 桌面程序最常见的场景是把收银台页面发给用户手机,用户用手机浏览器打开,所以 H5 支付是主路径,而不是扫码。
支付宝侧对应用户手机浏览器的是“手机网站支付”,接口方法叫 alipay.trade.wap.pay。它既能在浏览器里拉起支付宝 App,也能在网页收银台里完成支付,限制比微信少很多。微信 H5 支付有一个硬性边界:不能在微信内置浏览器里直接调起,页面会报环境异常,需要引导用户“在浏览器中打开”。这个不是 bug,是平台的规则,对接前就要在 H5 页面里做好提示。
选 H5 的另一个现实理由是前端可以随时改。支付环节最容易出问题,如果把它做成 Winform 里的一个窗体,每次调整金额校验、页面文案都要重新打包发布客户端,非常被动。把收银台做在 H5 里,后端只暴露下单和回调接口,前端页面可以独立部署迭代,两边互不拖累。
2.2 微信与支付宝在参数模型上的差异
很多第一次接支付的人以为两个平台共用一套代码,实际连最基础的参数结构都不一样。微信侧是“appid + mch_id + 商户支付密钥”,下单后返回 XML;支付宝侧是“app_id + 应用私钥 + 支付宝公钥”,下单后返回一段表单或字符串。下面这张表可以直接当字典用。
| 维度 | 微信 H5 支付 | 支付宝手机网站支付 |
|---|---|---|
| 商户标识 | appid + mch_id | app_id |
| 密钥体系 | API 密钥或 API v3 | 应用私钥 + 支付宝公钥 |
| 下单接口 | /pay/unifiedorder | alipay.trade.wap.pay |
| 下单返回 | XML,含 mweb_url | 表单 form 或表单串 |
| 回调格式 | XML POST | application/x-www-form-urlencoded 或 JSON |
| 金额单位 | 分(整数) | 元(可带两位小数) |
| 签名方式 | MD5 或 HMAC-SHA256 | RSA2(SHA256withRSA) |
微信统一下单成功后返回的是 mweb_url,H5 页面拿到它直接做 location 跳转;支付宝返回的是自动提交的 HTML 表单,前端要把这段 form 注入页面后 submit。两边的回调报文结构也完全不同,微信是 XML 节点,支付宝是键值对,解析代码没法复用,需要各写一套。
2.3 签名规则与金额进制:数据格式里最阴的两处
微信签名规则是:参数按键名 ASCII 升序排列,过滤空值,拼成 key=value&key=value 的形式,最后追加“&key=商户密钥”,做 MD5 后转大写。这里有一个隐藏细节:排序用的字典要保证升序,C# 里直接用 SortedDictionary 最稳,不要自己写排序。
// 微信支付签名:参数升序、过滤空值、末尾拼 key,MD5 后大写 string BuildWechatSign(SortedDictionary<string, string> dict, string key) { var sb = new StringBuilder(); foreach (var kv in dict) { if (!string.IsNullOrEmpty(kv.Value)) { sb.Append(kv.Key).Append('=').Append(kv.Value).Append('&'); } } sb.Append("key=").Append(key); return MD5(sb.ToString()).ToUpperInvariant(); }这段代码的逻辑顺序是:先确保字典已经按 key 排好序,再逐项拼接,值为空时跳过。最后拼上的 key 不参与排序,它只是签名的密钥尾巴。MD5 转大写是为了跟微信服务端的校验结果对齐,漏掉 ToUpperInvariant 是最常见的验签失败原因。
支付宝的 RSA2 签名逻辑不同:对业务参数按 key 排序后拼接,用应用私钥做 SHA256withRSA,服务端用支付宝公钥验签。常见误区是有人把支付宝公钥当成私钥拿去签名,或者把验签用的公钥配错。签名用的私钥和验签用的公钥是两把不同的钥匙,这一点在配置里要分清楚,写注释标明“私钥签名、公钥验签”。
金额进制也必须统一。微信 total_fee 的单位是分,传 1 元要传 100;支付宝 amount 单位是元,传 1.00。C# 里最稳妥的做法是全程使用 decimal 运算,只在调用微信接口前把金额转成整数分:(int)(Math.Round(amount * 100))。不要用 double 去算金额,浮点精度问题在支付场景里是真实翻车点,差一分钱订单都对不上。
3. 拆开 CSDN(pay).zip:后端工程与 H5 收银台怎么协作
如果你已经下载了 CSDN(pay).zip,解压后会看到两半:一半是 C# Winform 工程,另一半是 H5 页面文件。这一章把资源包的协作方式拆开讲,顺便说明前端页面在真实链路里承担什么角色。
3.1 资源包里的两半:Winform 工程与 H5 页面
这套资源不是一个单体项目,而是前后端分离的两段代码。Winform 工程里封装了下单、回调验签、订单状态处理这几块;H5 页面里是收银台和支付结果展示,测试链接 http://dumikj.com/pay.html 就是页面部署到服务器后的入口。页面必须用手机浏览器打开,因为 PC 浏览器很难模拟出真实的支付拉起环境。
前后端协作的完整链路是:手机浏览器访问 pay.html,用户输入金额并点击支付,页面把订单号和金额提交给 Winform 后端暴露的下单接口;后端调微信或支付宝下单接口,拿到 mweb_url 或支付表单返回给页面;前端跳转或提交表单,用户完成支付;支付平台异步把结果通知到后端的回调地址;后端验签后更新订单状态。
这条链路里,H5 页面只是“搬运工”和“展示层”,真正的判断逻辑全部在后端。前端可以随便换,后端接口保持稳定即可。所以改这套资源时,先别动 C# 下单逻辑,而是先把前端请求后端、后端返回跳转地址这一来一回跑通,再深入细节。
3.2 收银台页面:下单请求、拉起支付与回跳
H5 页面里最核心的一段逻辑是下单请求。下面是常见的写法,直接用 fetch 把订单金额提交到后端接口,后端返回跳转地址后交给浏览器处理:
// 收银台下单:把金额发给后端,拿到支付跳转地址 function createOrder() { const amount = document.querySelector('#amount').value; const orderNo = 'OD' + Date.now(); // 前端临时生成,正式场景以后端为准 fetch('http://你的后端地址:8080/api/createOrder', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'amount=' + encodeURIComponent(amount) + '&orderNo=' + orderNo }) .then(res => res.json()) .then(data => { if (data.code === 0) { // 支付宝场景 data.payForm 是一段表单,需要注入页面后 submit if (data.payForm) { const div = document.createElement('div'); div.innerHTML = data.payForm; document.body.appendChild(div); div.querySelector('form').submit(); } else if (data.payUrl) { // 微信 H5 场景直接跳转 mweb_url window.location.href = data.payUrl; } } else { alert(data.msg); } }) .catch(err => console.error('下单失败', err)); }这里的参数要点:amount 是用户输入的字符串,后端拿到后必须重新做格式校验和元分转换,不能直接信任前端数值;orderNo 在正式环境应该由后端生成,前端用 Date.now() 只是为了演示。返回结构里 payForm 和 payUrl 二选一,支付宝给表单,微信给跳转链接,前端做两个分支处理即可。
3.3 跨域与端口:H5 页面访问 Winform 接口的两个坑
第一个坑是地址。fetch 里如果写 localhost,手机访问页面时请求会打到手机自己身上,必然失败。调试阶段要把地址改成 PC 的局域网 IP,或者部署到公网服务器后换成域名。第二个坑是跨域。页面挂在 80 端口,后端监听 8080 端口,两边不同源,浏览器会拦截响应。Winform 没有 Web 项目里的 CORS 中间件,自己用 HttpListener 时需要手工加跨域头:
// Winform 后端返回 JSON 前手动追加跨域头 void WriteJson(HttpListenerResponse resp, string json) { resp.Headers["Access-Control-Allow-Origin"] = "*"; resp.Headers["Content-Type"] = "application/json; charset=utf-8"; var bytes = Encoding.UTF8.GetBytes(json); resp.OutputStream.Write(bytes, 0, bytes.Length); resp.Close(); }注意 Access-Control-Allow-Origin 设置为 * 只适合联调,生产环境建议改成实际部署 H5 页面的域名,否则任何网页都能调用你的下单接口,造成刷单风险。Content-Type 必须带 charset=utf-8,不然前端解析中文会乱码。后端写完响应要调用 Close 释放连接,否则前端会一直等不到结束符。
4. C# 下单与回调验签:把核心代码写成能直接用的版本
这一章是资源落地的主战场。Winform 工程里的下单和回调代码,核心逻辑可以抽象成四个部分:微信下单、支付宝下单、回调验签、本地回调服务挂载。每一部分我都给出可参考的代码骨架和参数说明。
4.1 微信 H5 统一下单:排序、签名、请求一次看完
微信 H5 下单走 unifiedorder 接口,trade_type 传 MWEB,成功后返回 mweb_url。代码骨架如下:
// 微信 H5 支付统一下单 public string WeiXinH5Pay(string orderNo, int totalFeeFen, string body) { var paras = new SortedDictionary<string, string> { ["appid"] = "wx你的AppId", ["mch_id"] = "16你的商户号", ["nonce_str"] = Guid.NewGuid().ToString("N"), ["body"] = body, ["out_trade_no"] = orderNo, ["total_fee"] = totalFeeFen.ToString(), // 单位:分 ["spbill_create_ip"] = "你的出口IP", ["notify_url"] = "https://你的域名/pay/wechat/notify", ["trade_type"] = "MWEB" }; // 第一步:生成签名并塞回参数集 var sign = BuildWechatSign(paras, MchKey); paras["sign"] = sign; // 第二步:转为 XML 并请求统一下单接口 var xml = ToXml(paras); var respXml = PostXml("https://api.mch.weixin.qq.com/pay/unifiedorder", xml); // 第三步:从返回 XML 中提取 mweb_url 返回给前端 var mwebUrl = ExtractXmlNode(respXml, "mweb_url"); if (string.IsNullOrEmpty(mwebUrl)) { Log("微信下单失败: " + respXml); return null; } return mwebUrl; }参数说明:out_trade_no 必须保证唯一,重复下单微信会直接报订单号已存在;total_fee 是整数分,不要在字符串里带小数点;spbill_create_ip 填写客户端出口 IP,部分场景微信会校验合法性;notify_url 必须是公网可访问的 HTTPS 或 HTTP 地址,不能写 localhost。
拿到 mweb_url 后,H5 页面直接跳转。用户支付完成后,微信会跳回 mweb_url 携带的 redirect_url 参数,这个回跳地址要在下单前就拼好,通常指向支付结果页。
4.2 支付宝手机网站下单:签出一段表单交给浏览器
支付宝手机网站支付的接口风格和微信完全不同,它不是提交 XML 等返回 URL,而是把所有业务参数拼接后用自己的私钥签名,然后返回一段会自动提交的 HTML 表单给前端。核心流程是构造参数、签名、生成 form:
// 支付宝手机网站支付:构造下单参数并生成自动提交表单 string AlipayWapPay(string orderNo, decimal amount, string subject) { var biz = new SortedDictionary<string, string> { ["out_trade_no"] = orderNo, ["total_amount"] = amount.ToString("0.00"), // 单位:元,两位小数 ["subject"] = subject, ["product_code"] = "QUICK_WAP_WAY" }; var paras = new SortedDictionary<string, string> { ["app_id"] = "你的支付宝AppId", ["method"] = "alipay.trade.wap.pay", ["charset"] = "utf-8", ["sign_type"] = "RSA2", ["timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), ["version"] = "1.0", ["notify_url"] = "https://你的域名/pay/alipay/notify", ["biz_content"] = JsonConvert.SerializeObject(biz) }; // 对参数做 RSA2 签名,签名串拼接规则与微信不同,不能复用 var signContent = string.Join("&", paras.OrderBy(p => p.Key) .Select(p => p.Key + "=" + p.Value)); var sign = Rsa2Sign(signContent, AliPrivateKey); // 生成自动提交表单:把参数和 sign 作为隐藏字段 var form = "<form id='alipayForm' action='https://openapi.alipay.com/gateway.do' method='POST'>"; foreach (var kv in paras) { form += $"<input type='hidden' name='{kv.Key}' value='{kv.Value}'/>"; } form += $"<input type='hidden' name='sign' value='{sign}'/>"; form += "</form><script>document.getElementById('alipayForm').submit();</script>"; return form; }注意 total_amount 是元,ToString("0.00") 强制保留两位小数,不要出现 1 被格式化成一元整的情况。biz_content 必须序列化成 JSON 字符串,里面不能出现中文字符转义问题,建议用 Newtonsoft.Json 统一序列化,避免自己拼字符串时漏掉引号。sign_type 固定 RSA2。
支付宝网关地址用 openapi.alipay.com/gateway.do,沙箱环境要换成 openapi.alipaydev.com/gateway.do。网关地址、app_id、私钥这三样东西建议统一放到配置文件里,切换测试和正式环境时只改一处,这样后面会省很多事。
4.3 回调验签与订单状态更新:核心中的核心
回调是支付对接里最容易被骗也被最容易被坑的地方。微信和支付宝的异步通知都不可信,必须验签,并且要用本地订单的金额做二次校验。下面是微信回调的处理骨架:
// 微信支付异步通知处理 void HandleWechatNotify(string xmlBody) { var dict = XmlToDict(xmlBody); // 微信回调是 XML 格式 // 第一步:协议层失败直接回退,不继续处理 if (dict["return_code"] != "SUCCESS") return; // 第二步:重新计算签名,与报文里的 sign 比对 var sign = BuildWechatSign(dict, MchKey); if (sign != dict["sign"]) { Log("微信回调验签失败: " + xmlBody); WriteNotifyResponse(false); return; } // 第三步:业务层失败也要记录 if (dict["result_code"] != "SUCCESS") { Log("微信支付结果失败: " + dict["out_trade_no"]); WriteNotifyResponse(false); return; } // 第四步:金额二次校验,以本地订单为准 var order = orderService.GetByOrderNo(dict["out_trade_no"]); if (order == null || order.AmountFen != int.Parse(dict["total_fee"])) { Log("订单不存在或金额不一致: " + dict["out_trade_no"]); WriteNotifyResponse(false); return; } // 第五步:幂等处理,已经成功的订单不重复改状态 if (order.Status == OrderStatus.Paid) { WriteNotifyResponse(true); return; } orderService.MarkPaid(order.OrderNo, dict["transaction_id"]); WriteNotifyResponse(true); } // 回 SUCCESS 字符串,微信收到后停止重发 void WriteNotifyResponse(bool ok) { var msg = ok ? "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>" : "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>"; // 将 msg 写入当前 HttpListener 响应流并关闭 }这段逻辑的顺序是刻意安排的:先验协议层,再验签名,再验业务结果,然后对金额,最后做幂等更新。不要一上来就改订单状态,否则伪造通知能把订单改成已支付。金额校验必须用本地数据库里的订单金额去比对回调里的 total_fee,而不是反过来相信回调。
回调响应必须返回 SUCCESS,否则微信会按策略重复通知,通常是一段时间内多次重试。如果业务处理失败,返回 FAIL,让微信继续重发。返回的 XML 里不要带多余空格或换行,CDATA 包裹的 SUCCESS 字符串是最稳妥的写法。
4.4 Winform 里挂一个回调服务:HttpListener 的用法
Winform 程序没有 IIS,也没有 ASP.NET 运行时,要在桌面程序里接收回调,最常见的做法是开一个 HttpListener 监听本地端口。代码结构并不复杂:
// 在 Winform 启动时挂起回调监听 void StartPayNotifyServer() { var listener = new HttpListener(); listener.Prefixes.Add("http://+:8080/pay/"); // 监听所有 IP 的 8080 端口 listener.Start(); var thread = new Thread(() => { while (listener.IsListening) { var ctx = listener.GetContext(); ThreadPool.QueueUserWorkItem(_ => ProcessNotify(ctx)); } }); thread.IsBackground = true; thread.Start(); } void ProcessNotify(HttpListenerContext ctx) { using (var reader = new StreamReader(ctx.Request.InputStream, Encoding.UTF8)) { var body = reader.ReadToEnd(); if (ctx.Request.Url.AbsolutePath.EndsWith("/wechat/notify")) HandleWechatNotify(body); else if (ctx.Request.Url.AbsolutePath.EndsWith("/alipay/notify")) HandleAlipayNotify(body); } }Prefixes 里的 http://+:8080/ 表示监听本机所有网卡的 8080 端口,这样手机通过局域网 IP 也能访问到。Windows 上监听非 localhost 端口可能需要管理员权限,如果启动时报拒绝访问,可以尝试用管理员身份运行,或者改用 http://localhost:8080/pay/ 配合内网穿透工具做公网映射。GetContext 是阻塞方法,不能放在 UI 线程里,否则 Winform 界面会卡死。
5. 支付联调避坑:五个真实场景,照着排查能少熬两夜
这一章是血泪经验汇总。微信支付和支付宝支付的联调过程里,大部分问题都集中在几个固定位置。每条按现象、原因、解决的顺序写,遇到问题时可以直接对照。
5.1 手机打开 pay.html 白屏,PC 上却正常
现象:PC 浏览器访问 pay.html 一切正常,手机浏览器打开却是白屏,控制台报错也看不到。原因通常是页面里引用了 localhost 的 JS 或接口地址,手机拿 localhost 去请求,自然加载失败;还有可能是页面混用了协议,页面本身是 HTTP,却引用了 HTTPS 资源,被移动端浏览器拦截。解决:把页面里所有资源引用改成相对路径或完整公网地址,接口地址改成局域网 IP 或域名;用手机浏览器自带的“查看网页源码”或远程调试工具打开控制台,看具体报错。
5.2 回调验签总是失败,日志里却看不出问题
现象:支付成功但订单一直不更新,后端日志显示验签失败。原因:微信回调验签失败往往是参与签名的字段里混入了空值或 sign 本身,重新拼接时必须过滤掉 sign 字段,空值节点要跳过;支付宝回调验签失败,最常见的是拿应用私钥去验签,而支付宝回调用的是支付宝公钥。解决:把收到的完整报文原样落盘到日志文件,对照官方文档检查参与签名的字段集合;验签用的公钥和下单用的私钥分别配置,不要顺手粘错。
5.3 金额对不上:差 100 倍或差 1 分钱
现象:订单在微信侧显示金额是 100 元,本地订单却记录成 1 元,或者总是差一两分。原因:微信以分为单位,H5 页面传上来的是元字符串,后端没有转换成整数分就直接提交;另一种原因是用了 double 做乘法,1.99 乘 100 在浮点环境里会得到 198.9999 之类的值,转 int 后丢一分。解决:后端统一用 decimal 接收前端金额,转换时用 (int)(Math.Round(amount * 100)),并且把转换函数单独抽出来写单元测试,至少覆盖 1.00、1.99、0.01 三个用例。
5.4 微信提示“当前页面的 URL 未注册”或调起失败
现象:点击支付后微信直接报错,提示当前页面 URL 未注册或支付权限受限。原因:微信 H5 支付要求商户平台配置支付授权目录和 H5 支付域名,测试环境的 IP 地址没有备案或未加入授权白名单。解决:登录微信商户平台,在“产品中心—H5 支付”里配置授权域名和支付目录;本地联调时用内网穿透工具绑定一个固定域名,把域名加进白名单,不要用随机端口地址反复测试。
5.5 支付宝沙箱一切正常,切换正式环境就失败
现象:沙箱环境里整个流程都能跑通,换成正式 app_id、正式密钥后下单直接报签名错误或无效参数。原因:沙箱环境和正式环境的网关地址、应用私钥、支付宝公钥三个配置互相混用,最常见的是把沙箱的公钥留在正式环境,或者网关还指向 openapi.alipaydev.com。解决:把网关地址、app_id、应用私钥、支付宝公钥拆成四个配置项,切换环境时整体替换一组,不要只改 app_id。上线前用正式环境跑一笔 0.01 元的真实支付,验证全链路。
6. 上线前的验证清单与一个能救命的回调调试技巧
6.1 回调调试最省事的方法:报文落盘加内网穿透
回调联调是整套资源里最磨人的环节,因为支付平台主动请求你的回调地址,本地 Winform 收不到。我一般会在回调处理函数的第一行就把原始报文写进日志文件,再把 Winform 的回调端口通过内网穿透工具暴露成一个公网地址,把这个地址配到微信和支付宝的 notify_url 里。这样每次支付完,本地日志立刻能看到完整报文,验签失败也能快速定位是字段问题还是密钥问题。
上线前记得把报文日志里的敏感字段脱敏,微信回调里会影响后续对账的字段可以保留,但不要记完整商户密钥。回调地址尽量不要用 IP,微信支付对 IP 回调的容忍度很低,绑定一个域名再做穿透或反代更稳定。
6.2 上线前按这张清单过一遍
最后整理一份验证清单,不算完整测试用例,但覆盖了最容易出问题的环节,照着走一遍能挡住大多数翻车现场。
| 检查项 | 通过标准 |
|---|---|
| 元分转换 | 1.99 元转微信分=199,支付宝提交=1.99 |
| 回调验签 | 微信/支付宝各用正式密钥验签通过 |
| 金额二次校验 | 回调金额不等于本地订单金额时拒绝改单 |
| 幂等处理 | 同一通知重复到达不重复改状态 |
| 回调返回 | 微信返回 SUCCESS 字符串,支付宝返回 success |
| 失败通知 | 验签失败时订单状态保持不变 |
| 日志 | 下单、回调、改单三个节点都有记录 |
| 域名白名单 | 微信授权目录、H5 支付域名已配置 |
我被金额单位坑过一次之后,接任何支付项目都强制先写一个元分转换的测试函数,回调里必须重新查库比对金额,而不是相信通知里的数字。这套 CSDN(pay).zip 的工程底子做得还算规矩,把参数替换成你自己的商户号,再按这份清单过一遍,微信和支付宝两条通道大概率不用返工。希望帮到你。
本文还有配套的精品资源,点击获取