1. 接入微信支付及商户信息设置
要实现微信小程序的支付功能,首先需要在微信小程序管理后台进行支付配置。进入微信小程序管理后台,找到「微信支付」选项,点击「接入微信支付」。如果是首次接入,选择「我还没有商户号」选项,按照指引完成商户号的申请流程。
完成商户号申请后,需要配置两个关键信息:
1. 设置支付授权目录:
在商户平台(pay.weixin.qq.com)中,进入「产品中心」→「开发配置」,添加支付授权目录。该目录需要与小程序后端支付接口的路径保持一致,确保支付请求的合法性。例如,如果你的支付接口路径是 https://yourdomain.com/api/pay
,则授权目录应填写 https://yourdomain.com/api/
。
2. 设置API密钥:
在商户平台的「账号中心」→「API安全」→「设置密钥」中,生成并保存API密钥。该密钥用于后续签名校验,务必妥善保管,避免泄露。
2. 开发小程序支付页面
在小程序前端,需要创建一个支付页面,通常包含金额输入框和支付按钮。以下是一个简单的页面结构示例:
<view>
<input placeholder="请输入金额" bindinput="inputAmount" />
<button bindtap="handlePay">立即支付</button>
</view>
在对应的JS文件中,处理用户输入并调用支付接口:
Page({
data: { amount: '' },
inputAmount: function(e) { this.setData({ amount: e.detail.value }); },
handlePay: function() {
if (!this.data.amount) return wx.showToast({ title: '请输入金额', icon: 'none' });
wx.request({
url: 'https://yourdomain.com/api/pay',
method: 'POST',
data: { amount: this.data.amount },
success: function(res) {
wx.requestPayment({
timeStamp: res.data.timeStamp,
nonceStr: res.data.nonceStr,
package: res.data.package,
signType: 'MD5',
paySign: res.data.paySign,
success: () => wx.showToast({ title: '支付成功' }),
fail: () => wx.showToast({ title: '支付失败', icon: 'none' })
});
}
});
}
});
3. 服务器端支付逻辑实现(PHP示例)
服务器端负责生成支付参数并签名。以下是一个PHP示例:
<?php
function generatePayParams($appid, $mch_id, $api_key, $openid, $amount) {
$nonceStr = md5(uniqid());
$timeStamp = time();
$outTradeNo = $mch_id . time(); // 商户订单号
// 统一下单API请求
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$params = [
'appid' => $appid,
'mch_id' => $mch_id,
'nonce_str' => $nonceStr,
'body' => '小程序支付',
'out_trade_no' => $outTradeNo,
'total_fee' => $amount * 100, // 单位为分
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'notify_url' => 'https://yourdomain.com/api/notify',
'trade_type' => 'JSAPI',
'openid' => $openid
];
// 生成签名
ksort($params);
$stringA = '';
foreach ($params as $k => $v) $stringA .= $k . '=' . $v . '&';
$stringSignTemp = $stringA . 'key=' . $api_key;
$sign = strtoupper(md5($stringSignTemp));
$params['sign'] = $sign;
// 请求微信接口
$xml = '<xml>';
foreach ($params as $k => $v) $xml .= "<$k>$v</$k>";
$response = curl_post($url, $xml);
$result = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA);
// 返回小程序支付参数
return [
'timeStamp' => "$timeStamp",
'nonceStr' => $nonceStr,
'package' => 'prepay_id=' . $result->prepay_id,
'signType' => 'MD5',
'paySign' => md5("appId=$appid&nonceStr=$nonceStr&package=prepay_id=$result->prepay_id&signType=MD5&timeStamp=$timeStamp&key=$api_key")
];
}
?>
4. 支付回调处理与验证
支付完成后,微信服务器会异步通知支付结果。需要在服务器端编写回调接口验证签名并处理业务逻辑:
<?php
function notifyCallback() {
$xml = file_get_contents('php://input');
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
// 验证签名
$sign = $data['sign'];
unset($data['sign']);
ksort($data);
$stringA = '';
foreach ($data as $k => $v) $stringA .= $k . '=' . $v . '&';
$stringSignTemp = $stringA . 'key=' . $api_key;
if ($sign !== strtoupper(md5($stringSignTemp))) exit('fail');
// 处理业务逻辑(如更新订单状态)
if ($data['return_code'] === 'SUCCESS') {
// 更新数据库订单状态为已支付
file_put_contents('notify.log', date('Y-m-d H:i:s') . json_encode($data) . "\n", FILE_APPEND);
}
echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
}
?>
5. 注意事项与常见问题
1. 金额单位:微信支付以分为单位,前端传入的金额需乘以100。
formSubmit:function(e){
let pp = e.detail.value;
if(pp.money.trim()=="")
{
wx.showToast({
title: "请输入捐赠金额!", //显示文本
icon: 'none', //使用图标
duration: 1000 //显示时间
})
return false;
}
// 注意,下面的reqest代码部分,that.data.userInfo.wid存储的就是当前用户的openid,这个信息一般会在用户登录后进行了存储,如果你没有存储,可以通过wx.login去获取,此处不再赘述
let that = this;
wx. request({
url:'刚刚在上面设置的安全支付目录地址/'+that.data.userInfo.wid+'/'+pp.money,
header: {
'content-type': 'application/json' // 默认值
},
success: function (ress){
// success
let res = ress.data;
if (res.status){
let out_trade_no = res.out_trade_no;//记录商户订单号 ,为后续缴费成功回调做记录
wx.requestOrderPayment ({
'timeStamp': res.timeStamp,
'nonceStr': res.nonceStr,
'package': res.package,
'signType': 'MD5',
'paySign': res.paySign,
'success': function(res3){
wx.showToast({
title: "支付成功,感谢您的善心!",
icon: 'success', //使用图标
duration: 1000 //显示时间
})
//此处负责回调,把先前的订单状态值为已付款
},
'fail':function (res2){
console.log (res2);
}
})
}
},
fail: function () {
//后台没连上
} ,
complete: function () {
// 处理结束
}
})
},
2. 域名配置:确保服务器域名已在小程序后台的「开发管理」→「开发设置」中配置。
3. 证书问题:如果使用退款功能,需在商户平台下载API证书。
4. 测试建议:正式上线前使用微信支付的沙箱环境测试(金额需≤1元)。
5. 安全提醒:API密钥和商户号属于敏感信息,不要明文存储在前端代码中。
通过以上步骤,即可完成微信小程序支付功能的完整接入。建议在实际开发中加入异常处理和日志记录,便于排查问题。
//支付调用的主函数, 名称需要和设置的商户支付授权目录一致
public function payOP(){
//获取opid和fee
$wid= $this->uri->segment(3,0); //获取小程序传过来的openid
$fee = $this->uri->segment(4,0);//获取小程序传过来的捐款
//设置参数
$appid = 'xxxxx';//小程序的appid ,如果是公众号 就是公众号的appid
$body = '本次支付的介绍,文字信息随便写';
$mch_id = '商户平台登录账号';
$nonce_str = $this->nonce_str();//随机字符串,下面会提供函数
$notify_url = '微信支付回调函数,说实话这个没啥用,不设应该不行,你就设置成你的reqest域名吧';
$openid = $wid;//当前支付用户的openid
$out_trade_no = date('YmdHis_', time()).ceil(microtime()*1000);//商户订单号,需唯一
$spbill_create_ip = '114.114.114.114';//随便一个真实存在的ip,必须要设置
$total_fee = $fee*100;//因为充值金额最小是1 而且单位为分 如果是充值1元所以这里需要*100
$trade_type = 'JSAPI';//交易类型 默认
//这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
$post['appid'] = $appid;
$post['body'] = $body;
$post['mch_id'] = $mch_id;
$post['nonce_str'] = $nonce_str;//随机字符串
$post['notify_url'] = $notify_url;
$post['openid'] = $openid;
$post['out_trade_no'] = $out_trade_no;
$post['spbill_create_ip'] = $spbill_create_ip;//终端的ip
$post['total_fee'] = $total_fee;//总金额 最低为一块钱 必须是整数
$post['trade_type'] = $trade_type;
$sign = $this->sign($post);//签名
$post_xml = '
'.$appid.'
'.$body.'
'.$mch_id.'
'.$nonce_str.'
'.$notify_url.'
'.$openid.'
'.$out_trade_no.'
'.$spbill_create_ip.'
'.$total_fee.'
'.$trade_type.'
'.$sign.'
';
//统一接口prepay_id
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$xml = $this->http_request($url,$post_xml);
$array = $this->xml($xml);//全要大写
if($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS'){
$time = time();
$tmp='';//临时数组用于签名
$tmp['appId'] = $appid;
$tmp['nonceStr'] = $nonce_str;
$tmp['package'] = 'prepay_id='.$array['PREPAY_ID'];
$tmp['signType'] = 'MD5';
$tmp['timeStamp'] = "$time";
$data['status'] = true;
$data['timeStamp'] = "$time";//时间戳
$data['nonceStr'] = $nonce_str;//随机字符串
$data['signType'] = 'MD5';//签名算法,暂支持 MD5
$data['package'] = 'prepay_id='.$array['PREPAY_ID'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
$data['paySign'] = $this->sign($tmp);//签名,具体签名方案参见微信公众号支付帮助文档;
$data['out_trade_no'] = $out_trade_no;
echo json_encode($data);
}else{
$data['status'] = false;
$data['text'] = "错误";
$data['RETURN_CODE'] = $array['RETURN_CODE'];
$data['RETURN_MSG'] = $array['RETURN_MSG'];
echo json_encode($data);
}
}
下面是一些上述代码需要调用的函数
//随机32位字符串
private function nonce_str(){
$result = '';
$str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
for ($i=0;$i<32;$i++){
$result .= $str[rand(0,48)];
}
return $result;
}
//签名 $data要先排好顺序
private function sign($data){
$stringA = '';
foreach ($data as $key=>$value){
if(!$value) continue;
if($stringA) $stringA .= '&'.$key."=".$value;
else $stringA = $key."=".$value;
}
$wx_key = '***************';//这里就是我上面讲解的设置了API的那个密钥 !!!
$stringSignTemp = $stringA.'&key='.$wx_key;
return strtoupper(md5($stringSignTemp));
}
private function xml($xml)
{
$p = xml_parser_create();
xml_parse_into_struct($p, $xml, $vals, $index);
xml_parser_free($p);
$data = "";
foreach ($index as $key=>$value) {
if($key == 'xml' || $key == 'XML') continue;
$tag = $vals[$value[0]]['tag'];
$value = $vals[$value[0]]['value'];
$data[$tag] = $value;
}
return $data;
}
private function http_request($url,$data = null,$headers=array())
{
$curl = curl_init();
if( count($headers) >= 1 ){
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
版权声明:本文为 “博览广文网” 原创文章,转载请附上原文出处链接及本声明;
工作时间:8:00-18:00
客服电话
0755-88186625
电子邮件
admin@lanyu.com
扫码二维码
获取最新动态