发表于 2018-05-19 17:43:11
支付主要分这几个步骤:
毫无疑问,首先肯定得在页面上有个支付的按钮 :-),按钮绑定事件。
<view class="container">
<button type="primary" bindtap="setLoading">支付button>
view>
// index.js
var app = getApp()
Page({
setLoading: function() {
var that = this
wx.login({
success: function(res) {
// 成功的话会返回:
// {errMsg: "login:ok", code: "获取用户OpenID的ticket"}
that.getOpenId(res.code)
}
})
}
})
小程序得到ticket后,不能自己获得用户OpenID(微信规定的),因此通过服务器代理
// index.js
var app = getApp()
Page({
setLoading: function() { ... }
getOpenId: function(jsCode) {
var that = this
wx.request({
url: https://myserver.com/login.php,
data: {
js_code: jsCode // wx.login()时得到的ticket
},
success: function (res) {
that.getPrePayId(res.data.openid)
}
})
},
getPrePayId: function() { // 后面讲到 }
})
服务器端代码(PHP):
// login.php
$params = [
appid => 小程序的appid,
secret => 小程序的secret,
js_code => $_GET[js_code], // 小程序传来的ticket
grant_type => authorization_code,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, https://api.weixin.qq.com/sns/jscode2session);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$output = curl_exec($ch);
if (false === $output) {
echo CURL Error: . curl_error($ch);
}
echo $output;
$output返回的是个JSON:
{
"session_key":"abcdefg",
"expires_in":7200, // 7200秒后失效,小程序要重新通过ticket获得一次OpenID
"openid":"abc123" // 用户的OpenID
}
得到OpenID后,再次请求服务器,让服务器代理调用统一下单接口:
// index.js
var app = getApp()
Page({
setLoading: function() { ... },
getOpenId: function() { ... },
getPrePayId: function(openId) {
var that = this
wx.request({
url: https://myserver.com/pay.php,
data: {
openid: openId
},
success: function(res) {
that.pay(res.data)
}
})
},
pay: function() { // 后面讲到 }
})
服务端代码:
$params = [
appid => 小程序的appid,
mch_id => 商户id,
// 随机串,32字符以内
nonce_str => (string) mt_rand(10000, 99999),
// 商品名
body => 鞋子,
// 订单号,自定义,32字符以内。多次支付时如果重复的话,微信会返回“重复下单”
out_trade_no => 20170823001 . time(),
// 订单费用,单位:分
total_fee => 1,
spbill_create_ip => $_SERVER[REMOTE_ADDR],
// 支付成功后的回调地址,服务端不一定真得有这个地址
notify_url => https://myserver.com/notify.php,
trade_type => JSAPI,
// 小程序传来的OpenID
openid => $_GET[openid],
];
// 按照要求计算sign
ksort($params);
$sequence = ;
foreach ($params as $key => $value) {
$sequence .= "$key=$value&";
}
$sequence = $sequence . "key=商户密钥";
$params[sign] = strtoupper(md5($sequence));
// 给微信发出的请求,整个参数是个XML
$xml = . PHP_EOL;
foreach ($params as $key => $value) {
$xml .= "<$key>$value$key>" . PHP_EOL;
}
$xml .= ;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, https://api.mch.weixin.qq.com/pay/unifiedorder);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$output = curl_exec($ch);
if (false === $output) {
echo CURL Error: . curl_error($ch);
}
// 下单成功的话,微信返回个XML,里面包含prepayID,提取出来
if (0 === preg_match(/ /, $output, $match)) {
echo $output;
exit(0);
}
// 这里不是给小程序返回个prepayID,而是返回一个包含其他字段的JSON
// 这个JSON小程序自己也可以生成,放在服务端生成是出于两个考虑:
//
// 1. 小程序的appid不用写在小程序的代码里,appid、secret信息全部由服务器管理,比较安全
// 2. 计算paySign需要用到md5,小程序端使用的是JavaScript,没有内置的md5函数,放在服务端计算md5比较方便
$prepayId = $match[1];
$response= [
appId => 小程序appid,
// 随机串,32个字符以内
nonceStr => (string) mt_rand(10000, 99999),
// 微信规定
package => prepay_id= . $prepayId,
signType => MD5,
// 时间戳,注意得是字符串形式的
timeStamp => (string) time(),
];
$sequence = ;
foreach ($response as $key => $value) {
$sequence .= "$key=$value&";
}
$response[paySign] = strtoupper(md5("{$sequence}key=商户密钥"));
echo json_encode($response);
最后,小程序发起实际的支付,界面上会弹出支付窗口
// index.js
var app = getApp()
Page({
setLoading: function() { ... },
getOpenId: function() { ... },
getPrePayId: function() { ... },
// data是服务端返回的JSON
// 加上success、fail回调后,正好符合wx.requestPayment()参数的格式
pay: function(data) {
data.success = function(res) {
// 用户支付成功后的代码
}
data.fail = function(res) {
// 用户支付失败后的代码
}
wx.requestPayment(data)
}
})