知識(shí)
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營銷的便利,運(yùn)營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!
您當(dāng)前位置>首頁 » 新聞資訊 » 小程序相關(guān) >
使用uniapp開發(fā)字節(jié)跳動(dòng)小程序的微信支付和支付寶支付
發(fā)表時(shí)間:2021-1-5
發(fā)布人:葵宇科技
瀏覽次數(shù):334
使用uniapp開發(fā)字節(jié)跳動(dòng)小程序的微信支付和支付寶支付(后端PHP,tp5)
準(zhǔn)備工作
- 微信支付配置
- 支付寶支付配置
- 字節(jié)跳動(dòng)配置
1,微信支付配置:
開通微信支付的h5支付,關(guān)聯(lián)APPID,保存key,商戶ID(mch_id ),配置回調(diào)域名,記得把字節(jié)跳動(dòng)的回調(diào)域名也寫進(jìn)h5支付的域名配置當(dāng)中:snssdk.com
2,支付寶支付配置:
開通支付寶的app支付,在網(wǎng)頁&移動(dòng)應(yīng)用中創(chuàng)建一個(gè)應(yīng)用接入app支付,并且簽約并且保證生效。我是通過支付寶證書進(jìn)行支付的,所以支付寶這邊需要自己去配置證書并且下載下來,后面要用到。
3,字節(jié)跳動(dòng)配置
開通字節(jié)跳動(dòng)的支付,獲得字節(jié)跳動(dòng)的商戶號(hào),appid,支付secret
業(yè)務(wù)代碼:
- 后端
- 前端
1,后端
上傳參數(shù),通過支付寶和微信配置訂單信息傳給前端uniapp,,微信和支付寶的回調(diào)正確的話,自己配置正確,按自己的情況添加訂單到數(shù)據(jù)庫就可以了,這里就不寫了。aliUrlZhengshu方法是支付寶支付,unifiedOrder方法是微信支付。
抖音的配置我寫在了config.php里面
'douyin'=>[
'appId'=>'*****',
'appSecret'=>'*****',
'url'=>'*****',//抖音授權(quán)鏈接
'payAppId' =>'*****',
'tt_pay_app_secret'=>'*****',//支付secret
'merchant_id'=>'*****',//支付secret
],
public function _initialize()
{
$this->appid = '*****';//微信的appid
$this->mch_id = '*****';//微信的商戶id
$this->key = '*****';//key
$this->notify_url = '*****';//自己配置的微信支付回調(diào)地址
}
public function payReady(){
$config = config('douyin');
$openid = $this->request->post('openid');
$truePrice = $this->request->post('price');
$video_id = $this->request->post('video_id');
$user_id = $this->request->post('user_id');
$subject = $this->request->post('subject');
$body = $this->request->post('body');
$truePrice = (int)$truePrice;
$tt_result = $this->ttOrder($user_id,$video_id,$truePrice,$subject,$body,$openid);
$out_order_no = $tt_result['out_order_no'];//自定義的訂單號(hào)
$arr = [
'merchant_id' =>$config['merchant_id'],//字節(jié)跳動(dòng)商戶號(hào) 前提條件->字節(jié)跳動(dòng)->4 完成填寫后
'app_id' => $config['payAppId'],//字節(jié)跳動(dòng)APPID 前提條件->字節(jié)跳動(dòng)->4 完成填寫后
'sign_type' => 'MD5',//定死的別動(dòng)!!!
'timestamp' => strval($tt_result['time']),//需要為字符串類型的時(shí)間戳
'version' => '2.0',//定死的別動(dòng)!!!
'trade_type' => 'H5',//定死的別動(dòng)!!!
'product_code' => 'pay',//定死的別動(dòng)!!!
'payment_type' => 'direct',//定死的別動(dòng)!!!
'out_order_no' => strval($out_order_no),//自定義的訂單號(hào)
'uid' => $openid,// 用戶的openid 登錄后可以獲取到
'total_amount' => $tt_result['fee'],//金額 這里單位:分
'currency' => 'CNY',//定死的別動(dòng)!
'trade_no' => $tt_result['out_order_no'],//剛剛獲取的字節(jié)跳動(dòng)訂單 忘了往上找找
'subject' => $tt_result['subject'],//之前定好的標(biāo)題
'body' => $tt_result['body'],//之前定好的內(nèi)容
'trade_time' => strval($tt_result['time']),//一定要和 上面的 timestamp 字段相同
'valid_time' => '3000',//測試留的時(shí)間長
'notify_url' => 'https://tp-pay.snssdk.com/paycallback',//定死的別動(dòng)!!!
];
$aliurl = $this->aliUrlZhengshu($tt_result);//獲取 alipay_url
$arr['alipay_url'] = $aliurl;
$wx_res = $this->unifiedOrder($tt_result['out_order_no'],$body,$subject);
if(!empty($wx_res)){
$pay_url = $wx_res;
}
$arr['wx_type'] = 'MWEB';
$arr['wx_url'] = $pay_url;
$stringToBeSigned = $this->getSignContent($arr);//這里待簽名處理.方法下面
$sign = md5($stringToBeSigned . $config['tt_pay_app_secret']);//這生成簽名咯, 不要亂, 簽名好多的
//這兩個(gè)字段的寫入原因: 在待簽名字符串 getSignContent 方法中不能有 sign和risk_info 所以在生成簽名($sign)之后寫入到里面
$arr['sign'] = $sign;
$arr['risk_info'] = json_encode(['ip' => request()->ip()]);
//這兩個(gè)字段的寫入原因: 在待簽名字符串 getSignContent 方法中不能有 sign和risk_info 所以在生成簽名($sign)之后寫入到里面
$res = htmlspecialchars_decode(json_encode($arr));//這里html的編譯解析, 防止html編譯
// $this->success('返回orderinfo', $res);
$this->success('返回orderinfo', ['list' => $res]);
}
/**
* 獲取抖音訂單號(hào)
*/
public function ttOrder($user_id,$video_id,$order_price,$subject,$body,$openid){
$config = config('douyin');
$time = time();
// if(!$user_id){
// $this->error('請(qǐng)先授權(quán)登錄');
// }
$price = $order_price*100;
//$price = 1;
//------------------自定義訂單信息--------------------------
$data = http://www.wxapp-union.com/['out_order_no' => $time, //隨便搞個(gè)訂單號(hào)
'openid' => $openid, //抖音用戶openid
'fee' => $price, //金額 單位:分!分!分!
'cid' => 1,
'time' => $time,
'body' => $body, //支付的內(nèi)容(支付寶)
'subject' => $subject, //支付的標(biāo)題(支付寶)
//body 和 subject 剛開始先用數(shù)字(中文會(huì)有其他問題)
];
//------------------自定義訂單信息--------------------------
//TP5框架 fastadmin
//------------------組合請(qǐng)求sign信息--------------------------
//↓↓↓獲取用戶真實(shí)IP
$risk_info = request()->ip();
//↓↓↓頭條支付分配給業(yè)務(wù)方的ID(不是頭條小程序的appid)
$payload['app_id'] = $config['payAppId'];
//↓↓↓頭條支付分配給業(yè)務(wù)方的支付秘鑰
$app_secret = $config['tt_pay_app_secret'];
//↓↓↓請(qǐng)求使用的編碼格式
$payload['charset'] = "utf-8";
//↓↓↓接口名稱
$payload['method'] = "tp.trade.create";
//↓↓↓發(fā)送請(qǐng)求的時(shí)間
$payload['timestamp'] = $time;
// 請(qǐng)求參數(shù)的集合 json
$biz_content = [
//商戶訂單號(hào)
"out_order_no" => $data['out_order_no'],
//唯一標(biāo)識(shí)用戶open_id
"uid" => $data['openid'],
//金額,分為單位,應(yīng)傳整型
"total_amount" => $data['fee'],
//商戶訂單名稱
"subject" => $data['subject'],
//商戶訂單詳情
"body" => $data['body'],
//頭條支付分配給業(yè)務(wù)方的商戶號(hào)
"merchant_id" => $config['merchant_id'],
//貨幣種類
"currency" => "CNY",
//下單時(shí)間戳
"trade_time" => $time,
//訂單有效時(shí)間(此處測試 時(shí)間留的長) 單位:秒
"valid_time" => "3000",
//服務(wù)器異步通知地址盡量https 沒試過http
"notify_url" => 'https://admin.shitutu.com/public/api/Dou_alipay/notify',
//用戶的真實(shí)ip 一定要json序列化
"risk_info" => json_encode(['ip' => $risk_info]),
];
$payload['biz_content'] = json_encode($biz_content);
//字節(jié)跳動(dòng)采用的是MD5加密
$payload['sign_type'] = "MD5";
$payload['format'] = "json";
$payload['version'] = "1.0";
//這里寫了一個(gè)簽名的方法, 千萬別亂, 此處簽名用來請(qǐng)求的, 與其他簽名沒有任何關(guān)聯(lián);(共3個(gè)簽名)
$stringToBeSigned = $this->getSignContent($payload, $payload['charset']);
$payload["sign"] = md5($stringToBeSigned . $app_secret);
$url = "https://tp-pay.snssdk.com/gateway"; // 請(qǐng)求地址正式環(huán)境
// $url = "$url?app_id=$payload[app_id]&secret=$appSecret&code=$code&anonymous_code=$anonymous_code";
$result = $this->file_get_contents_post($url, $payload);
/*返回示例:
{"response":{"code":"10000","msg":"Success","trade_no":"SP2020081509594510822988870791"},"sign":"E7RRJSJCVAhA4DMyMPr/Q1IOc1RKpyQNikl9l8b3ObW6dAYzep7rK6wY5YVjSubhmINsI0iWb/cu+YCqp1D+amifkXh4nX2JG3D0xgi2eWJrTv3Ou27zuEPbEb5y10SBG1f4QCYoa7r2upmOL5xbjY6kG5iDPjiS4JIthsojR5Q="}*/
$result = json_decode($result, true);
//------------------組合請(qǐng)求sign信息--------------------------
$res['out_order_no'] = $result['response']['trade_no'];
$res['fee'] = $price;
$res['cid'] = 1;
$res['time'] = $time;
$res['body'] = $body;
$res['subject'] = $subject;
$order_res = $this->order_create($user_id,$video_id,$order_price,$res['out_order_no']);//這里是我自己的創(chuàng)建訂單到本地?cái)?shù)據(jù)庫,這個(gè)方法就不展示了。
if ($result['response']['code'] != 10000) {
$this->error('錯(cuò)誤', $res['response']['code']);
} elseif ($res) {
return $res;
}
}
/**
* 簽名處理
* @param $params
* @param $charset
* @return string
*/
public function getSignContent($params, $charset = 'utf-8')
{
ksort($params);
$stringToBeSigned = "";
$i = 0;
foreach ($params as $k => $v) {
if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
// 轉(zhuǎn)換成目標(biāo)字符集
$v = $this->characet($v, $charset);
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
unset ($k, $v);
return $stringToBeSigned;
}
public function file_get_contents_post($url, $post) {
$options = array(
'http' => array(
'method' => 'POST',
// 'content' => 'name=caiknife&[email protected]',
'header' => "Content-type: application/x-www-form-urlencoded ",
'content' => http_build_query($post),
),
);
$result = file_get_contents($url, false, stream_context_create($options));
return $result;
}
/**
* @param $data
* @return mixed
* 阿里url證書
*/
public function aliUrlZhengshu($data)
{
//需要在AopCertClient.php文件中加入
//namespace app\api\controller;
//use think\Exception;
//引入文件 用來實(shí)例化
$config = config('douyin');
//require_once EXTEND_PATH . '/alipay/AopSdk.php';
require_once VENDOR_PATH . 'aop/AopCertClient.php';
// require_once EXTEND_PATH . 'aop/AopCertClient.php';
$c = new AopCertClient;
$appCertPath = VENDOR_PATH . 'aop/crt/appCertPublicKey_2021002114608375.crt';//應(yīng)用證書路徑(要確保證書文件可讀)
$alipayCertPath = VENDOR_PATH . 'aop/crt/alipayCertPublicKey_RSA2.crt';//支付寶公鑰證書路徑(要確保證書文件可讀)
$rootCertPath = VENDOR_PATH . 'aop/crt/alipayRootCert.crt';//支付寶根證書路徑(要確保證書文件可讀)
$c->gatewayUrl = "https://openapi.alipay.com/gateway.do";
$c->appId = self::APPID;
$c->rsaPrivateKey = self::RSA_PRIVATE_KEY;
$c->format = "json";
$c->charset = "UTF-8";
$c->signType = "RSA2";
//調(diào)用getPublicKey從支付寶公鑰證書中提取公鑰
$c->alipayrsaPublicKey = $c->getPublicKey($alipayCertPath);
//是否校驗(yàn)自動(dòng)下載的支付寶公鑰證書,如果開啟校驗(yàn)要保證支付寶根證書在有效期內(nèi)
$c->isCheckAlipayPublicCert = true;
//調(diào)用getCertSN獲取證書序列號(hào)
$c->appCertSN = $c->getCertSN($appCertPath);
//調(diào)用getRootCertSN獲取支付寶根證書序列號(hào)
$c->alipayRootCertSN = $c->getRootCertSN($rootCertPath);
//實(shí)例化具體API對(duì)應(yīng)的request類,類名稱和接口名稱對(duì)應(yīng),當(dāng)前調(diào)用接口名稱:alipay.open.public.template.message.industry.modify
//文件中加入 namespace app\api\controller; 即可
require_once VENDOR_PATH . 'aop/request/AlipayTradeAppPayRequest.php';
$request = new AlipayTradeAppPayRequest();
//此次只是參數(shù)展示,未進(jìn)行字符串轉(zhuǎn)義,實(shí)際情況下請(qǐng)轉(zhuǎn)義
$request->setBizContent($this->getcontent($data));
$response = $c->sdkExecute($request);
return $response;
}
/**
* @param $data
* @return false|string
* 業(yè)務(wù)數(shù)據(jù)
*/
public function getcontent($data)
{
$biz_content = array(
'out_trade_no' => $data['out_order_no'], //之前咱們自定義的訂單號(hào) out_trade_no
'product_code' => 'QUICK_MSECURITY_PAY', //定死了 別動(dòng)
'total_amount' => $data['fee'] / 100, //單位換算
'subject' => $data['subject'], //之前定好的 標(biāo)題
'method' => 'alipay.trade.app.pay', //定死了 別動(dòng)
'notify_url' => '*****',//回調(diào)接口需要配置到支付寶
'body' => $data['body'], //之前定好的 內(nèi)容
'timeout_express' => '1m', //支付超時(shí)時(shí)間 文檔去支付寶搜索咯 1m-15d
);
return json_encode($biz_content);
}
/**
* 下單方法
* param $params 下單參數(shù)
*/
public function unifiedOrder($order_no,$body,$subject){
$config = config('douyin');
$params['body'] = $subject; //商品描述
$params['out_trade_no'] = $order_no; //訂單號(hào)
$params['total_fee'] = 1; //金額是以分為單位,除測試外,需乘以100
$params['trade_type'] = 'MWEB'; //交易類型,h5支付,默認(rèn)如此
$params['scene_info'] = $body; //場景信息,h5固定
$params['spbill_create_ip'] = $this->getIp(); //終端IP
$params['appid'] = $this->appid;
$params['mch_id'] = $this->mch_id;
$params['nonce_str'] = $this->genRandomString(); //隨機(jī)字符串
$params['notify_url'] = $this->notify_url; //通知地址
//獲取簽名數(shù)據(jù)
$params['sign'] = $this->MakeSign( $params ); //簽名
$xml = $this->data_to_xml($params);
$uri = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //請(qǐng)求地址
$response = $this->postXmlCurl($uri,$xml); //自定義封裝的xml請(qǐng)求格式,文章最下面為參考postxml
if( !$response ){
return false;
}
$result = $this->xml_to_data( $response );
if( !empty($result['result_code']) && !empty($result['err_code']) ){
$result['err_msg'] = $this->error_code( $result['err_code'] );
}
if($result['result_code'] == 'SUCCESS' && $result['return_msg'] == 'OK'){
//發(fā)起微信支付url
$pay_url = $result['mweb_url'];//.'&redirect_url='.urlencode($this->notify_url)
}else{
$pay_url = '';
}
return $pay_url;
//return $result;
}
/**
* 生成簽名
* @return 簽名
*/
public function MakeSign( $params ){
//簽名步驟一:按字典序排序數(shù)組參數(shù)
ksort($params);
$string = $this->ToUrlParams($params);
//簽名步驟二:在string后加入KEY
$string = $string . "&key=".$this->key;
//簽名步驟三:MD5加密
$string = md5($string);
//簽名步驟四:所有字符轉(zhuǎn)為大寫
$result = strtoupper($string);
return $result;
}
/**
* 輸出xml字符
* param $params 參數(shù)名稱
* return string 返回組裝的xml
**/
public function data_to_xml( $params ){
if(!is_array($params)|| count($params) <= 0)
{
return false;
}
$xml = "<xml>";
foreach ($params as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
/**
* @param $url
* @param $xml
* @param int $second
* @return bool|string
* xml請(qǐng)求
*/
public function postXmlCurl($url,$xml,$second = 30){
$ch = curl_init();
//設(shè)置超時(shí)
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
//設(shè)置 header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求結(jié)果為字符串且輸出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post 提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//運(yùn)行 curl
$data = http://www.wxapp-union.com/curl_exec($ch);
//返回結(jié)果
if($data){
curl_close($ch);
return $data;
}else{
$error = curl_errno($ch);
curl_close($ch);
echo"curl 出錯(cuò),錯(cuò)誤碼:$error"."<br>";
}
}
/**
* 將xml轉(zhuǎn)為array
* param string $xml
* return array
*/
public function xml_to_data($xml){
if(!$xml){
return false;
}
//將XML轉(zhuǎn)為array
//禁止引用外部xml實(shí)體
libxml_disable_entity_loader(true);
$data = http://www.wxapp-union.com/json_decode(json_encode(simplexml_load_string($xml,'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $data;
}
/**
* 校驗(yàn)$value是否非空
* @param $value
* @return boolean;
* if not set ,return true;
* if is null , return true;
**/
public function checkEmpty($value)
{
if (!isset($value))
return true;
if ($value =http://www.wxapp-union.com/== null)
return true;
if (trim($value) ==="")
return true;
return false;
}
/**
* 轉(zhuǎn)換字符集編碼
* @param $data
* @param $targetCharset
* @return string
*/
public function characet($data, $targetCharset)
{
if (!empty($data)) {
$fileType = "UTF-8";
if (strcasecmp($fileType, $targetCharset) != 0) {
$data = http://www.wxapp-union.com/mb_convert_encoding($data, $targetCharset, $fileType);
}
}
return $data;
}
復(fù)制代碼
2,前端,uniapp
我是通過字節(jié)跳動(dòng)的收銀臺(tái)吊起的支付的,吊起收銀臺(tái)后可以選擇支付寶或者微信支付,然后跳轉(zhuǎn)到微信或者支付寶,所以上面要把微信和支付寶的支付url都傳給了前端。
gopay(){
wxpay({
'openid':'****',
'price':'****',
'video_id':'****',
'user_id':'****',
'subject':'****',
'body':this.detailList.title,
}).then(e => {
let order = JSON.parse(e.data.data.list);
let order_no = order.trade_no
if(e.data.code == 1){
uni.requestPayment({
service: 1, // 不拉起字節(jié)跳動(dòng)小程序收銀臺(tái)
_debug: 1,
payChannel: {
default_pay_channel: 'alipay' // wx || alipay
},
orderInfo: order, // 訂單信息
getOrderStatus(res) {
let { out_order_no } = res;
return new Promise(function (resolve, reject) {
})
},
success: (res) => {
console.log(res)
if(res.code == 0){
uni.showToast({
title: '支付成功',
duration: 2000
});
}
if(res.code == 1){
uni.showToast({
title: '支付超時(shí)',
duration: 2000
});
}
if(res.code == 2){
uni.showToast({
title: '支付失敗',
duration: 2000
});
}
if(res.code == 2){
uni.showToast({
title: '支付失敗',
duration: 2000
});
}
if(res.code == 4){
orderQuery({
'order_no':order_no,
}).then(e => {
if(e.data.code == 1){
uni.showToast({
title: '支付成功',
duration: 2000
});
}else{
uni.showToast({
title: '支付失敗',
duration: 2000
});
}
});
}
if(res.code == 9){
uni.showToast({
title: '訂單狀態(tài)未知',
duration: 2000
});
}
},
fail: (res) => {
console.log("失敗1");
console.log(res); // 錯(cuò)誤代碼:CD0015 CD0025
},
complete: (res) => {
console.log("結(jié)束")
}
})
// _this.loadModal = false;
}
})
},
復(fù)制代碼
這里有一個(gè)問題我不知道是不是字節(jié)官方的原因,我通過收銀臺(tái)支付,使用支付寶支付的時(shí)候,支付成功,返回小程序是有字節(jié)的支付回調(diào)頁面并且提示成功的。但是微信支付沒有顯示這個(gè)支付回調(diào)的頁面提示,并且code一直是4,所以我在code等于4的時(shí)候去后端驗(yàn)證了一下支付狀態(tài),手動(dòng)給用戶提示了支付狀態(tài),如果有朋友知道原因可以麻煩告知我一下,有問題也歡迎留言。
相關(guān)案例查看更多
相關(guān)閱讀
- 小程序開發(fā)平臺(tái)前十名
- 云南手機(jī)網(wǎng)站建設(shè)
- 昆明做網(wǎng)站
- web開發(fā)技術(shù)
- 云南小程序開發(fā)
- 小程序被騙
- 昆明小程序開發(fā)
- 云南網(wǎng)站建設(shè)制作
- 云南衛(wèi)視小程序
- 保山小程序開發(fā)
- 云南網(wǎng)站建設(shè)價(jià)格
- 網(wǎng)站沒排名
- 網(wǎng)站維護(hù)
- 小程序開發(fā)課程
- 高端網(wǎng)站建設(shè)公司
- 云南小程序被騙
- 云南小程序商城
- 昆明小程序代建
- 怎么做網(wǎng)站
- 云南小程序開發(fā)推薦
- 汽車報(bào)廢回收管理系統(tǒng)
- 文山小程序開發(fā)
- 云南網(wǎng)絡(luò)營銷顧問
- Web開發(fā)框架
- 小程序開發(fā)
- 迪慶小程序開發(fā)
- 昆明軟件定制公司
- 云南網(wǎng)站制作
- asp網(wǎng)站
- 網(wǎng)站小程序