最新文章
前端对接微信 H5 支付及防盗刷验证技术文档
发布时间:2026-09-11
热度:
前端对接微信 H5 支付及防盗刷验证技术文档
文档类型:HTML 技术文档,可直接浏览器打开阅读,包含:业务流程、前后端对接代码示例、防盗刷安全方案、风险点、踩坑总结。 说明:微信 H5 支付核心签名、统一下单、验签全部必须后端完成,前端只负责唤起支付,前端不能做签名,防止密钥泄露;防盗刷是前后端协同实现。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>前端对接微信H5支付及防盗刷验证技术文档</title> <style> * { box-sizing: border-box; } body { font-family: "Microsoft Yahei", system-ui, sans-serif; max-width: 1100px; margin: 0 auto; padding:20px; background:#f5f7fa; line-height:1.75; color:#222; } .doc-wrap { background:#fff; padding:32px 40px; border-radius:10px; box-shadow: 0 1px 6px #00000014; } h1 { text-align:center; color:#07C160; margin-top:0; } h2 { border-left:4px solid #07C160; padding-left:12px; margin-top:32px; } h3{ margin-top:24px; } pre { background:#272822; color:#fff; padding:16px; border-radius:6px; overflow-x:auto; } code{ background:#efefef; padding:2px 6px; border-radius:3px; } pre code{ background:transparent; } .warn{ background:#fff3cd; border:1px solid #ffd380; padding:14px 16px; border-radius:6px; margin:16px 0; } .danger{ background:#ffe9e9; border:1px solid #ffbaba; padding:14px 16px; border-radius:6px; margin:16px 0; } .tip{ background:#e8f4ff; border:1px solid #b8d8ff; padding:14px 16px; border-radius:6px; margin:16px 0; } table{ width:100%; border-collapse: collapse; margin:16px 0; } table th,table td{ border:1px solid #ccc; padding:10px 12px; } table th{ background:#f3f6f9; } .toc{ background:#f7f8fa; padding:18px 22px; border-radius:8px; } </style> </head> <body> <div> <h1>前端对接微信H5支付及防盗刷验证技术文档</h1> <div> <strong>目录</strong> <ol> <li><a href="#chapter1">1 业务概述与前置条件</a></li> <li><a href="#chapter2">2 完整业务交互流程</a></li> <li><a href="#chapter3">3 前端实现代码示例</a></li> <li><a href="#chapter4">4 防盗刷、防恶意下单安全验证方案(重点)</a></li> <li><a href="#chapter5">5 后端核心职责说明</a></li> <li><a href="#chapter6">6 常见坑与排错</a></li> <li><a href="#chapter7">7 安全红线总结</a></li> </ol> </div> <h2 id="chapter1">1 业务概述与前置条件</h2> <h3>1.1 什么是微信H5支付</h3> <p>微信H5支付(外部浏览器H5支付):在微信以外浏览器唤起微信支付,跳转微信客户端完成付款,区别于微信内置浏览器JSAPI支付。</p> <div> <strong>⚠️重要限制:</strong>微信H5支付<strong>不能在微信内置浏览器使用</strong>;微信内网页需要使用JSAPI支付。 </div> <h3>1.2 开通前置条件</h3> <ul> <li>① 微信支付商户号,已开通H5支付权限;</li> <li>② 商户后台配置H5支付授权域名;</li> <li>③ 后端保存:商户号 mch_id、API密钥key、商户证书;</li> <li>④ 业务域名完成ICP备案;</li> <li>⑤ 用户访问环境:手机浏览器、APP内嵌webview(非微信内置浏览器)。</li> </ul> <h3>1.3 角色分工</h3> <table> <tr> <th>端</th> <th>职责</th> </tr> <tr> <td>前端H5</td> <td>收集业务参数、安全校验、请求后端获取支付跳转链接、跳转微信支付、处理回调页面、防盗刷前端拦截</td> </tr> <tr> <td>业务后端</td> <td>统一下单接口调用、生成H5支付url、生成防盗刷token、订单幂等、回调通知验签、风控校验</td> </tr> <tr> <td>微信支付服务端</td> <td>统一下单、用户收银台、支付结果异步回调</td> </tr> </table> <h2 id="chapter2">2 完整业务交互流程</h2> <ol> <li>用户在H5页面选择商品,提交下单;<strong>前端做第一层防盗刷校验</strong>(人机验证、token校验)</li> <li>前端将业务参数、风控参数传给后端;</li> <li>后端执行防盗刷二次校验,校验通过调用微信统一下单接口;</li> <li>微信返回mweb_url(H5支付跳转地址);后端生成业务token返回前端;</li> <li>前端拿到mweb_url,页面跳转,唤起微信客户端;</li> <li>用户微信完成付款;</li> <li>微信跳回商户设置的H5支付回调页面;</li> <li>微信服务器<strong>异步通知后端支付结果</strong>(以异步通知为准,前端返回页面仅做展示,不能作为订单成功依据);</li> <li>后端更新订单状态;前端回调页轮询后端接口展示订单支付结果。</li> </ol> <div> <strong>重点:绝对不能依靠前端跳转回来判断支付成功!支付结果唯一可信来源是微信后端异步回调通知。</strong> </div> <h2 id="chapter3">3 前端实现代码示例</h2> <h3>3.1 下单页面(唤起H5支付)</h3> <pre><code><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>H5支付下单页</title> </head> <body> <div> <p>商品:会员充值 99元</p> <button id="payBtn">立即微信支付</button> </div> <script> const payBtn = document.getElementById('payBtn'); payBtn.addEventListener('click', async () => { // =========【前端防盗刷前置校验】========= // 1.防止重复点击 payBtn.disabled = true; payBtn.innerText = "请求中..."; // 2.获取后端下发的防重token(页面渲染后端下发,存入localStorage) const antiCsrfToken = localStorage.getItem("antiOrderToken"); if(!antiCsrfToken){ alert("页面异常,请刷新重试"); payBtn.disabled = false; payBtn.innerText = "立即微信支付"; return; } try { // 请求后端接口,获取微信H5支付mweb_url const res = await fetch("/api/wxh5pay/createOrder",{ method:"POST", headers:{ "Content-Type":"application/json" }, body: JSON.stringify({ productId:1001, // 防盗刷相关参数传给后端校验 antiCsrfToken: antiCsrfToken, userAgent: navigator.userAgent, clientIp:"" //ip建议后端获取 }) }) const data = await res.json(); if(data.code === 200){ // mweb_url:微信H5支付跳转链接 const mwebUrl = data.data.mweb_url; // return_url 是支付完成跳转回来的商户页面,微信会拼接参数返回 // 执行跳转唤起微信H5支付 window.location.href = mwebUrl; }else{ alert(data.msg || "下单失败"); } }catch(err){ alert("网络异常,请重试"); }finally { payBtn.disabled = false; payBtn.innerText = "立即微信支付"; } }) </script> </body> </html> </code></pre> <h3>3.2 支付回调返回页面 return_url</h3> <p>用户微信付款结束后,微信会跳转到这个页面,url携带部分参数;<strong>只做展示,不能当做支付成功凭证,需要请求后端查询订单真实状态。</p> <pre><code><!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>支付结果页</title> </head> <body> <div id="resultText">正在查询支付结果...</div> <script> // 获取url上的订单号参数 const urlParams = new URLSearchParams(window.location.search); const outTradeNo = urlParams.get('out_trade_no'); async function queryPayResult(){ const resp = await fetch(`/api/wxh5pay/queryResult?outTradeNo=${outTradeNo}`); const json = await resp.json(); const dom = document.getElementById("resultText"); if(json.code ===200 && json.data.paySuccess){ dom.innerText = "✅支付成功!"; }else if(json.code ===200 && !json.data.paySuccess){ dom.innerText = "❌未支付或支付失败,请重新下单"; }else{ dom.innerText = "查询异常,请稍后刷新"; } } // 页面加载查询一次,简单轮询2次 queryPayResult(); setTimeout(queryPayResult,2000); </script> </body> </html> </code></pre> <h2 id="chapter4">4 防盗刷、防恶意下单安全验证方案(重点)</h2> <div> H5支付风险:爬虫批量刷下单、脚本恶意请求、重复提交、CSRF跨站伪造请求、恶意爆破;防盗刷需要<strong>前端拦截 + 后端严格校验,缺一不可</strong>。 </div> <h3>4.1 前端层防护(第一道拦截,不能信任)</h3> <ol> <li><strong>防重复提交:按钮置灰,禁止短时间重复点击下单按钮;</strong></li> <li><strong>防重Token(Anti‑CSRF token)</strong>:页面渲染由后端生成一次性token,存入localStorage,下单请求必须携带,token只能使用一次,后端校验销毁;阻止跨站脚本伪造下单请求。</li> <li>UA采集上报:提交下单带上navigator.userAgent,后端用于风控比对。</li> <li>人机验证(图形验证码/滑块):高风险场景下单前弹出人机校验,拦截脚本。</li> <li>页面禁止表单自动重复提交,增加最小操作间隔,禁止F12脚本快速调用接口。</li> </ol> <h3>4.2 后端核心防盗刷校验(真正生效,不可省略)</h3> <ol> <li>校验一次性antiCsrfToken,校验完成立即销毁,不可重复使用;</li> <li>IP风控:限制同一IP短时间下单频次,超过阈值拦截;</li> <li>用户账号风控:同一账号N分钟内最大下单次数,防止刷单;</li> <li>幂等校验:外部商户订单号 out_trade_no 全局唯一,避免重复创建订单;</li> <li>校验userAgent,异常UA直接拒绝下单;</li> <li>金额校验:传入支付金额和业务数据库商品价格比对,防止前端篡改金额;</li> <li>微信统一下单接口后端调用,<strong>私钥、支付密钥绝不暴露前端</strong>;</li> <li>微信异步回调通知严格验签,验证签名,校验商户号、订单号、金额,拒绝伪造回调。</li> </ol> <h2 id="chapter5">5 后端核心职责说明</h2> <h3>5.1 统一下单接口关键参数(微信H5支付)</h3> <p>接口地址:<code>https://api.mch.weixin.qq.com/pay/unifiedorder</code></p> <ul> <li>trade_type:MWEB(H5支付固定值)</li> <li>mweb_url:返回H5跳转地址,前端用来跳转</li> <li>scene_info:必须传入,h5_info -> type:WAP,传入H5网站域名</li> <li>notify_url:支付异步回调地址,公网可访问,POST</li> <li>out_trade_no:商户唯一订单号</li> <li>total_fee:单位分,金额</li> </ul> <div> scene_info参数缺失,会直接报H5支付调用失败! </div> <h3>5.2 异步回调注意点</h3> <ul> <li>微信异步通知会多次重试,后端必须<strong>幂等处理,同一订单多次通知只更新一次状态</strong></li> <li>返回给微信字符串 <code><xml><return_code><![CDATA[SUCCESS]]></return_code></xml></code>,告诉微信接收成功;否则微信持续重试推送。</li> <li>回调接口禁止重定向,只输出xml文本。</li> </ul> <h2 id="chapter6">6 常见坑与排错</h2> <table> <tr> <th>现象</th> <th>原因</th> <th>解决方案</th> </tr> <tr> <td>微信内置浏览器打开H5支付报错</td> <td>H5支付不支持微信内置webview</td> <td>前端判断UA,如果是微信内置浏览器,切换JS‑API支付</td> </tr> <tr> <td>统一下单返回:H5‑SYS‑ERR</td> <td>未配置H5支付域名,scene_info参数错误</td> <td>商户平台配置授权域名,补全scene_info参数</td> </tr> <tr> <td>支付完成跳转return_url,但订单状态不变</td> <td>把前端页面跳转当做支付成功,没有处理微信异步回调</td> <td>以微信后端notify_url异步通知为准,return_url仅做展示查询</td> </tr> <tr> <td>脚本刷接口恶意下单</td> <td>缺少token、IP频次、人机校验防盗刷</td> <td>补齐前后端全套防盗刷校验,后端做核心拦截</td> </tr> </table> <h2 id="chapter7">7 安全红线总结</h2> <ul> <li>❌禁止前端保存、暴露微信支付API密钥、商户证书;签名、统一下单<strong>全部后端执行</strong>。</li> <li>❌禁止前端页面跳转回调return_url作为订单支付成功判断依据。</li> <li>❌不要信任前端传来的金额,后端数据库做价格比对校验,防止篡改金额。</li> <li>✅防盗刷:前端只是缓解,所有风控逻辑必须后端二次校验。</li> <li>✅所有订单状态变更,以微信支付异步回调通知为准。</li> <li>✅CSRF防重token一次性使用,使用完成销毁。</li> </ul> <div> <strong>补充:UA判断微信环境前端工具片段</strong> <pre><code>/** 判断是否微信内置浏览器 */ function isWeChatBrowser(){ return /MicroMessenger/i.test(navigator.userAgent); } // 如果是微信内置浏览器,禁用H5支付入口,引导JS‑API支付 </code></pre> </div> </div> </body> </html>












冀公网安备