JSAPI支付必须使用已认证公众号的AppID,且需配置JSAPI授权目录和安全域名;统一下单后前端调起支付前须由后端独立签名;异步回调需用php://input解析XML并严格验签;沙箱环境需单独配置密钥与接口地址。

JSAPI支付必须用公众号的 AppID,不是开放平台或小程序的
微信 JSAPI 支付只认公众号(服务号)的 APPID,哪怕你把开放平台的 APPID 或小程序的 APPID 填进去,调用 unifiedorder 接口也会返回 INVALID_REQUEST: invalid appid。这是最常卡住的第一步。
确认方式:登录公众号后台 →「开发」→「基本配置」→ 看「公众号开发信息」里的 AppID(格式类似 wx1234567890abcdef),且该公众号必须已认证、开通微信支付、并完成 JSAPI 支付授权目录配置。
- 授权目录必须精确到二级路径,比如你跳转支付页是
https://example.com/pay/index.php,就得填https://example.com/pay/(结尾带斜杠) - 测试时可用本地域名(如
http://localhost:8080/),但需在公众号后台「JS接口安全域名」中添加,且仅限调试,正式环境必须是备案域名 + HTTPS - 后端统一下单接口中传的
appid、openid(用户在该公众号下的唯一标识)、trade_type=JSAPI三者必须严格匹配
统一下单接口返回 prepay_id 后,前端调用 wx.chooseWXPay 前要重签名
很多人以为后端返回 prepay_id 就能直接丢给前端调起支付,其实不行。微信要求前端发起支付前,必须由后端生成一个临时签名(timestamp、nonceStr、package、signType、paySign),且这个签名和统一下单时的签名算法、密钥、参数组合完全独立。
关键点:
立即学习“PHP免费学习笔记(深入)”;
微信聊天分析助手 v2.1.0 — 完全本地运行的隐私保护工具。 分析聊天记录,推断 MBTI 与大五人格,检测情感趋势,生成可视化报告。 支持 jieba 精准分词、否定识别、反讽检测、风险预警。 内置 RAG 检索增强预测和多智能体博弈模拟,完全本地化、零数据外传。 可选 MiroFish 群体智能引擎增强对话预测。
- 后端要构造参数字典:
appId(公众号 AppID)、timeStamp(秒级时间戳,不是毫秒)、nonceStr(随机字符串,建议用uniqid()或random_bytes(16)转 hex)、package(固定值prepay_id=xxx)、signType(推荐MD5或HMAC-SHA256,注意前后端一致) - 签名原文拼接顺序必须严格按 key 升序(
appId、nonceStr、package、signType、timeStamp),再拼上key=商户APIv3密钥 - 别漏掉
timeStamp是整数类型,PHP 里用(string)time(),不是date('U')—— 后者也对,但更易错
回调通知验签失败?别直接解析 raw body,要用 file_get_contents('php://input')
微信支付服务器发来的异步通知是原始 XML,Content-Type 为 application/xml,PHP 默认不会把它塞进 $_POST。如果你写了 if ($_POST['return_code'] === 'SUCCESS'),永远进不去。
正确做法:
- 用
$xml = file_get_contents('php://input')拿到原始数据 - 用
simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)解析,再转成数组(注意LIBXML_NOCDATA防止 CDATA 内容被忽略) - 验签前先检查
$data['return_code'] === 'SUCCESS'和$data['result_code'] === 'SUCCESS',两者都通过才继续 - 验签用的签名串,必须从原始 XML 中提取
sign字段,并用剩余字段(不含sign)按字典序拼接 + 密钥计算,不能从数组里随便取值再拼——顺序错一点就失败
沙箱环境跑不通?先确认是否启用了沙箱密钥和沙箱下单接口
微信支付沙箱不是“自动切换”,它是一套独立环境:有独立的沙箱 API 密钥、独立的沙箱下单地址、甚至独立的模拟支付成功逻辑。直接拿生产配置去调沙箱,必然报 INVALID_SIGNATURE 或 NOAUTH。
实操要点:
- 登录微信商户平台 →「账户中心」→「API安全」→「沙箱」→ 下载沙箱 API 证书并启用,拿到沙箱
API密钥(不是生产密钥) - 统一下单请求地址要换成沙箱版:
https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder - 沙箱下单返回的
prepay_id是模拟值,前端调起后会弹出固定金额的模拟支付页,不扣真实钱;但回调通知仍是真实 HTTP 请求,需照常处理 - 沙箱不支持 JSAPI 的
getBrandWCPayRequest调试工具验证,只能靠真机扫码测试
最麻烦的是:沙箱验签用的密钥和生产不同,且沙箱回调通知里的 sign 是用沙箱密钥算的,如果代码里写死密钥没做环境区分,这里就静默失败。


















