[TOC]
## 前言
完成微信h5支付的你,繼續公眾號的支付也許更簡單哦。
## 場景
微信瀏覽器中的應用支付必須依賴于公眾號支付,下面就公眾號支付中的一些技術點進行詳細的解析。
## 準備工作
### 基本配置申請
參考資料:[微信公眾號開通支付功能--百度經驗教程](https://jingyan.baidu.com/article/636f38bb48c6fcd6b9461071.html)
### 基本信息
* 服務號,服務號綁定的管理員號
* 開通支付賬號,并記住支付賬號,與支付賬號綁定的微信號
* appid,秘鑰
* 支付賬號開通支付目錄(**直接支付地址的上一級目錄**)
* **設置了頁面授權域名,并且是你的站點域名地址**
* **基本接口權限**,尤其是jssdk部分權限,保證盡可能都開通
### 業務流程圖解以及時序圖
與微信h5基本相同,唯一不同的是這次微信返回的需要喚起微信sdk支付的參數列表。
## 技術問題
### 獲取openid
網站應用微信登錄是基于OAuth2.0協議標準構建的微信OAuth2.0授權登錄系統。獲取openid分為兩步,獲取code,然后根據code獲取openid,建議這兩部分請求由后端發起,前端直接請求會涉及到跨域問題。后端直接把這兩個方法定義為工具方法,使用方便,便于其他場景的復用。
#### 一 :請求獲取code,如果不想浪費時間請直接復制粘貼使用
* 標準格式拼接代碼:
~~~
let encodeUrl=encodeURIComponent(`http://xxx/xhxwxpay?productId=${productId}&orderNo=${orderNo}`)
let tempUrl=`https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx6f5de09c8ef178a7&redirect_uri=${encodeUrl}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`
~~~
* 請求參數說明
| 參數 | 是否必須 | 說明 |
| --- | --- | --- |
| appid | 是 | 應用唯一標識 |
| redirect_uri | 是 | 請使用urlEncode對鏈接進行處理 |
| response_type | 是 | 填code |
| scope | 是 | 應用授權作用域,擁有多個作用域用逗號(,)分隔,網頁應用目前僅填寫snsapi_login即可,這里用的 snsapi_userinfo |
| state | 否 | 用于保持請求和回調的狀態,授權請求后原樣帶回給第三方。該參數可用于防止csrf攻擊(跨站請求偽造攻擊),建議第三方帶上該參數,可設置為簡單的隨機數加session進行校驗 |
* **返回說明:**
用戶允許授權后,將會重定向到redirect_uri的網址上,并且帶上code和state參數
`redirect_uri?code=CODE&state=STATE`
若用戶禁止授權,則重定向后不會帶上code參數,僅會帶上state參數
`redirect_uri?state=STATE`
* 參考文檔:[微信中web網站獲取code參考文檔](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN)
#### 二 根據code獲取openid
* 一個用戶針對一個公眾號openid是固定的,所以獲取到一樣的不用懷疑,涉及到部分敏感的公眾號的秘鑰等,建議是后端處理發起請求,這樣也可以避免前端跨域的問題。
~~~
//網關或者后端的設置(以koa框架的為例)
*post_getOpenId(){
let reqData = this.request.body;
let param = {
appid:'wxxxx',
secret:'affsdcsdvdsvfv6',
code:reqData.code,
grant_type:'authorization_code'
}
let result = yield this.api.getOpenId(param);
this.body = result;
}
// 獲取openid 傳入對象的形式,改造通用的api方法
getOpenId: function* (apiParam, json = true) {
// 獲取token的地址
let apiUrl='https://api.weixin.qq.com/sns/oauth2/access_token'
let response = yield request.get(apiUrl, { qs: apiParam, json: json });
return responseHandle(response, apiUrl, apiParam);
}.bind(this),
//前端的寫法,好處是避免暴露公眾號的相關信息
this.$api.post("order/getOpenId", { code: this.code }).then(res => {
// 正確獲取openid的情況下 請求后臺參數得到對應的返回參數,目前只需要openid
if (res.openid) {
this.openId = res.openid;
//準備條件足夠的話 可以喚起支付
this.topay()
}else {
//請求失敗或者沒有對應的字段
}
~~~
* 請求參數說明,通過code獲取access_token
~~~
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
~~~
| 參數 | 是否必須 | 說明 |
| --- | --- | --- |
| appid | 是 | 應用唯一標識,在微信開放平臺提交應用審核通過后獲得 |
| secret | 是 | 應用密鑰AppSecret,在微信開放平臺提交應用審核通過后獲得 |
| code | 是 | 填寫第一步獲取的code參數 |
| grant_type | 是 | 填authorization_code |
* 返回結果說明
~~~
//正確的返回
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
//錯誤的返回
{"errcode":40029,"errmsg":"invalid code"}
~~~
* 刷新fresh-token有效期
如果token失效了,可以用refresh_token重新獲取一個。
### 微信支付sdk
#### 方式一 :官網的方式
invoke方法 ,簡單有效,直接根據接口返回參數喚起。以下代碼實例是vue環境下的,其他環境請自行匹配,僅供參考。
~~~
// 準備好微信sdk部分
jsSdk(){
// 判斷微信的WeixinJSBridge
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', this.onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', this.onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', this.onBridgeReady);
}
}else{
this.onBridgeReady();
}
},
// 支付sdk準備完成
onBridgeReady() {
// 觸發微信支付
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
appId: this.payOption.appId, //公眾號名稱,由商戶傳入
timeStamp: this.payOption.timeStamp, //時間戳,自1970年以來的秒數
nonceStr: this.payOption.nonceStr, //隨機串
package: this.payOption.package, //prepay_id用等式的格式
signType: this.payOption.signType, //微信簽名方式:
paySign: this.payOption.paySign, //微信簽名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
// 支付成功 返回成功頁
let tempUrl="//paysucc"
location.href=tempUr
} else{
// 取消支付或者其他情況 get_brand_wcpay_request:cancel get_brand_wcpay_request:fail
let tempUrl='//topay'
location.href=tempUrl
}
}
);
},
~~~
#### 方式二 : 需要引入js-weixin的模塊,流程如下:
引入模塊--ready--獲取access-token--獲取ticket--生成簽名(wx.config需要)--結合接口返回參數--喚起wxpay。(比較麻煩,不推薦使用)
參考文檔:
## 參考文檔
* [設置支付目錄以及回調域名](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3)
## 其他
- [微信支付java指南](https://mp.weixin.qq.com/s/VQJivfo3_rUMoqgAsj-_uQ)
- 前端入門
- 前端入職須知
- 入職準備
- 前端ide
- vsc快速上手指南
- 上手指南一
- 常用插件推薦
- 微信開發者
- sublime的使用
- hbuilder入門
- ws
- 前端面試
- 概要
- bat面試題庫
- 題庫一
- 面試大綱
- 題庫二
- 面試大綱
- 前端基礎面試題
- js基礎面試題
- vue&&react面試題
- 數據結構&&算法面試題
- 題庫三
- 001
- 題庫四
- 中小公司leader
- 常規題庫
- 前端規范
- 001
- css
- 001
- 002
- es6(js)
- 001
- 002
- 003
- 004
- node
- 001
- vue
- 001
- react
- 001
- 預處理器
- 001
- gulp
- 001
- webpack
- 001
- 設計模式
- 001
- web常識
- 001
- koa
- 001
- 小程序
- 001
- 數據結構與算法
- 001
- 推薦文章
- 面試指南
- web性能
- 面試分享
- 001
- ps
- ps入門階段
- 圖片類型以及區別
- 基本概念以及常用工具
- ps操作技巧
- 幾個問題
- ps互動教程軟件(app)
- 資源導航
- ps站點資源導航
- ui站點導航
- html
- h5專題
- audio/video
- Geolocation
- Websockets
- Web storage
- Communication
- Web Workers
- requestAnimationFrame
- async&&defer
- fileApi
- h5調用底層能力
- input新解
- canvas實戰篇
- 教程
- js
- javascript入門
- js代碼審查工具
- js性能優化
- 瀏覽器dom對象
- js優質資源
- indexDB入門
- jquery
- jq基本語法
- jq插件與原生插件
- Jq使用建議
- ajax后退解決方案
- jq常見問題
- js常用技術
- js控制運動-move.js
- 常用正則歸納
- js實用技術
- 鼠標行為分析
- document.referrer
- 你可能不知道的調試技巧
- 表格文件的讀取與下載
- 異步編程那些事
- 數據結構
- 編程環境和模型
- 列表
- 棧
- 隊列
- 鏈表
- 字典
- 散列
- 集合
- 二叉樹和二叉查找樹
- 參考
- js編程
- js模塊機制
- 算法
- 基本算法
- 遞歸
- 圖和圖算法
- 圖定義
- 系統建模
- 圖類
- 搜索圖
- 查找最短路徑
- 拓撲排序
- 圖實踐
- 排序算法
- 測試平臺
- 冒泡排序
- 選擇排序
- 插入排序
- 基本排序的比較
- 希爾排序
- 歸并排序
- 快速排序
- 實踐
- 二分排序
- 檢索算法
- 順序查找
- 二分查找
- 查找文本數據
- 檢索實踐
- 高級算法
- 動態規劃
- 貪心算法
- 高級算法實踐
- 代碼重構
- 簡化函數參數
- 001
- 002
- 基礎鞏固
- 001
- es2015實戰
- 初識es-module
- 異步編程
- es6工廠函數
- filter|map|reduce
- js實戰篇
- 前端圖像處理
- touch事件知多少
- 手勢與實踐
- print表格分頁
- 精彩文章推薦
- 001
- 插件庫
- 插件大全
- 功能性插件
- pdfjs
- wdatepicker
- qrcoder
- barcode插件
- photoviewer
- hammer.js
- echarts
- 視頻控件
- 發送瀏覽器通知
- 觸屏簽名插件
- 圖片相關插件推薦
- 待分類插件(pc)
- 待分類插件(手機端)
- 交互組件
- layerjs
- web
- web兼容
- pc端兼容bug匯總
- ie兼容bug匯總
- ie8測試專題
- web常用技術點
- web兼容匯總001
- ie6專題
- css兼容
- web安全
- web安全初級
- app/h5組件
- app教程
- 前端教程
- rubikx的教程
- 與app交互邏輯
- h5喚起app通識
- webview專題
- webview總綱
- js與oc交互協議
- js與安卓交互協議
- 兼容問題匯總
- jsBridge專題
- errorBook.js
- 常用工具
- chrome-devtool使用
- chraels
- 開發注意事項
- web常識
- markdown教程
- 自定義風格思路
- 經驗與問題總結
- 總結1
- 前端應該注意哪些seo
- 懶加載和預加載
- https
- 前端重構
- web優化
- 移動端web優化
- http緩存
- web端優化
- 圖片專題
- svg專題
- 深入淺出svg
- 地圖使用
- 注意事項
- 需求提交
- 常規交互需求提交
- 緩存
- 干貨文章
- 瀏覽器緩存
- 內存
- web性能指南
- 讀書筆記
- ui框架
- 概論
- easyui
- bootstrap
- 入門推薦
- modal插件使用
- 按鈕組件
- 正確使用柵格布局
- 下拉框插件使用
- 表單使用與驗證
- tab切換項插件
- 分頁控件
- 進度條控件
- 文件上傳控件
- 面板控件
- 常見特效與插件
- weui
- sui-pc
- sui-mobile
- layerUI
- frozen-UI
- rubik-u那些事
- 基本內容
- 小程序
- 小程序入門
- 入門
- 實踐踩坑
- 001
- 基本語法
- 開發大綱
- 注意事項
- 微信專題
- 基本入門
- 準備工作
- 定制菜單
- 圖文消息與圖文推送
- h5支付
- 公眾號支付
- node完成微信支付
- 進階使用
- 微信分享
- weui使用
- 基本使用
- 支付寶專題
- 支付寶h5支付
- app支付接入
- 服務窗支付
- java
- java入門
- eclipse基本使用
- 語言特點
- java代碼規范
- 編譯調試
- java基本語句
- springMVC
- javaweb
- vm模板引擎
- freemarker
- 常用常識
- 常用常識2
- 部署項目
- web --xml文件解析
- java生成pdf文件
- java讀取、寫文件案例
- 圖片加水印
- 圖片加水印2
- java-cookie
- 驗證碼文件
- sql-mapper語法
- maven教程
- mySql教程
- jeecms
- flash
- flash入門
- flash準備工作
- 運行與編譯
- 瀏覽器中flash設置教程
- flash檢測