在实际开始编码前,请允许我们对微信公众号支付进行更详细的讨论。微信支付看似高深莫测,实则如同一个神秘的宝盒,其中蕴含着诸多未知与挑战。今日,让我们共同揭开这层神秘面纱,探寻其内部奥秘。
一、准备工作:目录结构和证书文件
我们需确保项目目录明晰规范。类比于杂乱无章的房间,混乱的目录会消耗寻找资料的时间。因此,我们将商户证书文件(包括PEM和P12格式)存放在wxpay下的cert目录中。此证书犹如我们的身份证明,缺少则无法透过后台进行微信支付操作。
前端需将充值金额传送至后端。此操作犹如在线上银行进行取号,前端负责获取序号,而后端则专注于处理业务流程。在此过程中,还须获取用户授权以获取用户个人信息,并将其存储于系统之中。这一环节类似于银行柜员对客户身份的核实,以确保交易安全可靠。
二、统一下单操作:签名和回调地址
在接收到前端发来的充值金额信息之后,我们需执行统一下单操作,这类似于银行柜员对您的提现请求进行处理。在此环节,我们将添加特定数据,如自定义参数,这些数据将在查询API及支付通知中原封不动地返回。
//请求支付,提交支付金额,让后台进行统一下单操作
function charge() {
var money = $('#money').val();
$.ajax({
url:header_url+'pay/pay', //后台接收数据,进行统一下单操作的地址,填你自己的
dataType:'json',
type:'POST',
data:{'money':money},
success:function (data) {
//后台统一下单完成,返回前端数据中包含预支付订单的各种参数
var res = eval('('+data+')');
//调起支付
callpay(res['data']);
}
})
}
需设定一个回调地址作为通知系统,便于银行在处理完提现请求后告知您结果。此回调地址须为外网可访问的URL且不可带参。
三、签名验证:一个都不能少
统一下单流程中,签名至关重要,其角色犹如银行防伪技术,确保所有交易真实且有效。必须遵循规定对相关参数实施签名程序,以获取签名结果。尽管此步骤较为繁琐,却不可或缺。
曾经历过一次误区,即签名认证失败。运用PHP代码直接验证,却依旧收到同样的错误提示。经过多次核实统一下单流程,仍未找到问题所在。最终,在仔细研读相关文档后,方知支付过程中参数排列顺序至关重要。原来,官方示例中的预付款订单参数顺序存在错误!此误区令人啼笑皆非。
四、回调处理:结果的真相
在前端接收到支付结果时,只需执行页面跳转操作,无需额外处理。此过程类似于银行柜员告知您已完成提现操作,然而实际结果仍需参考银行系统记录。因此,请以回调地址中的实际反馈为准。
关于回调地址接收支付结果数据模式,敬请参阅相应API文档以获取详情。此流程类似于银行系统对于提现请求的最后确认阶段。值得注意的是,回调地址所接收的数据是否均由微信服务器发出?亦或是存在数据泄漏风险,他人获知您的回调URL后,向该地址发送虚假支付结果通知数据。因此,在接收到数据后,务必进行签名验证,以确保其真实性,如同银行系统对您身份的二次核实,确保无误。
五、实战经验:那些年我们踩过的坑
在项目实施过程中,各类问题层出不穷。如签名验证失利、参数顺序颠倒以及回调地址伪造等现象,相当于道路上的阻碍。然而,仔细研究相关文件并遵循操作规程后,这些挑战反而能助推我们前进。
public function pay() {
$tools = new \JsApiPay();
if($this->request->isPost()){
$data = input('post.');
$money = $data['money'] *100; //微信支付以分为单位
$logHandler= new \CLogFileHandler(EXTEND_PATH."pay/wxpay/logs/".date('Y-m-d').'.log');
$log = \Log::Init($logHandler, 15);
//①、获取用户openid
$openId = session('openid');
$userId = session('id');
$input = new \WxPayUnifiedOrder();
$input->SetBody("test"); //商品描述
$input->SetAttach($userId); //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
$input->SetOut_trade_no(\WxPayConfig::MCHID.date("YmdHis"));//商户订单号
$input->SetTotal_fee($money);//订单金额
$input->SetTime_start(date("YmdHis"));//交易起始时间
$input->SetTime_expire(date("YmdHis", time() + 600));//交易结束时间
$input->SetGoods_tag("test"); //订单优惠标记,使用代金券或立减优惠功能时需要的参数,实际上这里可以不要
$input->SetNotify_url("http://www.xxxx.com/wechat/index.php/server/pay/notify");//接收回调通知地址
$input->SetTrade_type("JSAPI"); //支付类型
$input->SetOpenid($openId); //用户openid
$order = \WxPayApi::unifiedOrder($input); //统一下单,该方法中包含了签名算法
$jsApiParameters = $tools->GetJsApiParameters($order); //统一下单参数
//将统一下单接口生成的预支付订单参数返回给前端,前端就可以调取支付了
return getBack(1,$jsApiParameters);//getBack是我自定义的方法,就是给前端ajax请求返回json格式数据,1代表成功,这里你要自己修改。
}else {
//下面是展示前端页面的,与统一下单无关
$openId = session('openid');
$this->assign('user',session('username'));
$this->assign('openId',$openId);
return $this->fetch('recharge');
}
}
曾遭遇签名验证失利困境,经多次查验仍未找出症结所在。
六、总结:微信支付,你真的懂了吗?
透过本文,我们深入探讨了微信公众号支付的全过程,涵盖从前期筹备到统一下单执行,以及签名验证与回调处理等各个环节。尽管每个阶段均存在潜在风险,但只要我们认真研读相关文档,严格遵循规范步骤,便能将其转化为推动进步的动力。
//前端吊起支付
//jsApiParameters是后台返回的预支付订单各种参数的json格式数据
function callpay(jsApiParameters) {
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', jsApiCall(jsApiParameters), false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', jsApiCall(jsApiParameters));
document.attachEvent('onWeixinJSBridgeReady', jsApiCall(jsApiParameters));
}
}else{
jsApiCall(jsApiParameters);
}
}
愿此文助您绕过微信支付的曲折,加速迈入支付高阶。
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
,
function(res){
WeixinJSBridge.log(res.err_msg);
alert(res.err_code+res.err_desc+res.err_msg);
}
);
}
七、互动时间:你遇到过哪些坑?
在研发历程中,您遭遇过何种困境?例如签名校验未通过,参数排列不当,抑或是回调地址遭篡改等。请将您的经验与经历分享于此,共同探讨,共同成长。若本篇文章对您有所裨益,敬请点赞并分享。
//前端吊起支付
function jsApiCall(jsApiParameters) {
var jsApiParameters = eval('(' + jsApiParameters + ')');
console.log(jsApiParameters);
WeixinJSBridge.invoke(
'getBrandWCPayRequest',{
"appId":jsApiParameters['appId'], //公众号名称,由商户传入
"timeStamp":jsApiParameters['timeStamp'], //时间戳,自1970年以来的秒数
"nonceStr":jsApiParameters['nonceStr'], //随机串
"package":jsApiParameters['package'],
"signType":jsApiParameters['signType'], //微信签名方式:
"paySign":jsApiParameters['paySign']//微信签名
},
//上面参数一定要按照一定的顺序排列,否则会出错(签名验证失败)
function(res) {
//前端接收到支付结果通知,get_brand_wcpay_request:ok,支付成功
//(但是不一定就是真的成功了,一切以回调地址中的结果为准,前端接收到支付通知后只做跳转,不做任何处理)
//商户订单处理(更新用户账号余额)要放在回调地址中处理
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
//支付成功,跳转到其他页面
location.href=header_url+'index/balance';
}
}
);
}