微信公眾號支付實現詳解(前端)

RobinsonZhang發表於2018-02-06

前言

完成微信h5支付的你,繼續公眾號的支付也許更簡單哦。

場景

微信瀏覽器中的應用支付必須依賴於公眾號支付,下面就公眾號支付中的一些技術點進行詳細的解析。

準備工作

基本配置申請

參考資料:微信公眾號開通支付功能--百度經驗教程

基本資訊

  • 服務號,服務號繫結的管理員號
  • 開通支付賬號,並記住支付賬號,與支付賬號繫結的微訊號
  • 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參考文件

二 根據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。(比較麻煩,不推薦使用) 參考文件:

參考文件

相關文章