時間過得飛快,轉眼間從業前端已經有些年頭了,見了太多的場景,意想不到的的錯誤,以爲自己足夠成熟和冷靜的時候,支付再一次教了我一回,怎麼做一個人。。。
事情的經過大致是這樣子的,公司有一個h5新項目,然後再開發的時候需要對接支付。經過調研,後來只打算上微信支付和支付寶支付,在這裏首先對支付寶支付api的開發者表示致敬,真心好用。然後再說會微信。。。。有h5支付,公衆號支付,還有小程序支付。。。。在這裏奉勸大家,如果是真的設計多方登錄,支付的時候,還是使用微信開放平臺把,畢竟找個屬於少生優生,幸福一生的選擇,不然也有可能會有我接下來的經歷。。。
h5支付寶支付
大概調起支付的過程如下:
創建訂單信息
拿到返回表單
渲染表單
表單進行提交
<!-- 1. 正常使用ajax提交商品信息,後臺返回內容如下 -->
<form id='alipaysubmit' name='alipaysubmit' action='https://openapi.alipay.com/gateway.do?charset=UTF-8' method='POST'><input type='hidden' name='biz_content' value='{****}'/><input type='hidden' name='app_id' value='*******'/><input type='hidden' name='version' value='1.0'/><input type='hidden' name='format' value='json'/><input type='hidden' name='sign_type' value='RSA2'/><input type='hidden' name='method' value='alipay.trade.wap.pay'/><input type='hidden' name='timestamp' value='2020-06-10 08:56:10'/><input type='hidden' name='alipay_sdk' value='alipay-sdk-php-20161101'/><input type='hidden' name='notify_url' value='******'/><input type='hidden' name='return_url' value='http://starmall.ipxmall.com/order/order-result'/><input type='hidden' name='charset' value='UTF-8'/><input type='hidden' name='sign' value='*****/******+******+****/****+****=='/><input type='submit' value='ok' style='display:none;''></form><script>document.forms['alipaysubmit'].submit();</script>
- 客戶端調用, 項目使用vue,直接貼上組件,將上邊的內容當作參數傳入組件就ok
需要注意的是,因爲是表單,所以需要使用v-html進行數據綁定,然後正常調起支付就ok了
<template>
<div v-html="info">
</div>
</template>
<script>
export default {
props: {
info: String
},
data() {
return {}
},
watch: {
info() {
this.$nextTick(() => {
document.querySelector('#alipaysubmit').submit()
})
}
}
}
</script>
<style>
</style>
微信支付之網頁支付
大概步驟和上述相同,需要提一下的是,微信h5支付只能在手機瀏覽器才能測試
- 調用後臺接口,創建訂單(微信支付需要初始化jsapi)
- 發起支付
// 需要注意的是:判斷是否在微信內置瀏覽器(微信內置瀏覽器使用jsapi調起支付,手機瀏覽器使用url跳轉)
if (!this.isWeiXin) {
let { errorCode, data } = await payInfo(params)
if (errorCode === 0) {
window.location.href = data
}
return false
}
// 到此爲止,瀏覽器微信支付搞定
微信內置瀏覽器支付調起
- 初始化微信支付jsapi
initWxPay() {
let wxSrc = 'https://res.wx.qq.com/open/js/jweixin-1.2.0.js'
let script = document.createElement('script')
script.src = wxSrc
document.body.append(script)
}
~~2. 返回內容… 等等,居然報錯了 , ~~
發現統一下單需要openid, openId 只能客戶端首先進行getCode,然後服務器通過code拿到openid,然後統一下單。再然後返回客戶端需要的信息
2. getCode
// 需要緩存商品信息,或者將訂單信息的ID通過state攜帶過去,回調處理會簡單很多
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=${state}#wechat_redirect`
- 重定向會到我們的頁面,回調的url裏就會有code
// 1. 拿到code, 然後創建訂單信息
const { code } = this.$route.query
// 2. 統一下單,然後,判斷是否在微信內置瀏覽器(微信內置瀏覽器使用jsapi調起支付,手機瀏覽器使用url跳轉)
// 3. 然後創建訂單信息
- 發起支付
let { errorCode, data } = await payInfo({ 訂單信息, code })
if (errorCode === 0) { // 判斷後臺返回值正確以後調起支付
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
}
// 爲了方便查看,將方法放到後邊,data是後臺統一下單後給的返回信息
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": data.appId, //公衆號名稱,由商戶傳入
"timeStamp": `${data.timeStamp}`, //時間戳,自1970年以來的秒數
"nonceStr": data.nonceStr, //隨機串
"package": data.package,
"signType":"MD5", //微信簽名方式:
"paySign": data.paySign //微信簽名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ){
// 使用以上方式判斷前端返回,微信團隊鄭重提示:
self.$router.replace('/order/order-result')
}
});
}
// 正常輸入密碼,完成支付
微信小程序內嵌網頁調起小程序支付
.小程序新建一個支付頁面,接受參數,完成後續的步驟
支付流程如下:
- 從內嵌網頁使用小程序暴露的api跳轉到小程序支付頁面,(講sku信息傳遞過去)
- 小程序在onload的時候讀取到信息,然後使用wx.login拿到code,
- 將sku信息和code通過結果發送給後臺,後臺統一下單
- 拿到後臺統一下下單後的返回信息,調起小程序支付
- 輸入密碼,完成支付, 代碼如下
// h5網頁內代碼
if (window.__wxjs_environment === 'miniprogram') {
// 將需要用到的信息都傳遞過去,方便在小程序調用的時候使用
// token id, sku信息
wx.miniProgram.reLaunch({
url: `/pages/h5-pay/main?data=${JSON.stringify({params, token})}`
})
return false
}
export default {
name: 'index',
data() {
return {
// path: 'https://ipxh5.jfshare.com'
}
},
methods: {
// 完成訂單後跳轉
reLaunch(status) {
wx.redirectTo({
url: `/pages/h5-result/main?status=${status}`
})
},
// 登錄獲取code
login(options) {
options = JSON.parse(options)
let { token, params } = options
wx.setStorage({
key:"token",
data: JSON.stringify(token)
})
let self = this
wx.login({
success (res) {
if (res.code) {
//發起網絡請求
self.initPayInfo({code: res.code, ...params})
} else {
console.log('登錄失敗!' + res.errMsg)
}
}
})
},
// 發起支付
async initPayInfo(params) {
let self = this
let { errorCode, data } = await request.post('/order/order/createOrderPayInfo', params)
if (errorCode === 0 ) {
wx.requestPayment({
...data,
signType: 'MD5',
success (res) {
self.reLaunch(1)
},
fail (res) {
self.reLaunch(0)
}
})
}
}
},
// 這裏拿到傳遞過來的參數
onLoad(options) {
if (options.data) {
this.login(options.data)
}
}
}
結束語
- 在安卓部分機型會在網頁關閉後清空當前頁面用到的所有緩存(cookie, sessionstorage, localstorage), 這裏需要做處理
- 關於支付的順序 的處理,減少判斷的嵌套層級
- 假如出現以上類似公衆號支付和小程序支付的appid不一樣的情況下的處理(需要後端配合)
- 調試,記得一定要用vsconsole, 記得一定要讓後臺在調試過程中一直打開日誌
- 小程序調試使用開發者工具即可