微信支付之微信H5支付(坑,ajax不支持重定向跳轉)


這里講的是  微信h5支付,    是微信以外的手機瀏覽器調用微信h5支付

 

 h5支付:

H5支付是指商戶在微信客戶端外的移動端網頁展示商品或服務,用戶在前述頁面確認使用微信支付時,商戶發起本服務呼起微信客戶端進行支付。
主要用於觸屏版的手機瀏覽器請求微信支付的場景。可以方便的從外部瀏覽器喚起微信支付。

 

一、基本信息和配置

在基本配置的之初請參考【公眾號支付】 的前面部分,
不同的是H5支付需要申請通過才能使用,申請的地方是商戶平台 產品中心>我的產品,申請通過如下:

 

 在開發配置里配上H5支付的域名:

 

 

基本信息配置到此,下面開始敲代碼

二、開發支付

建議參考微信H5開發文檔
https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1

微信H5支付開發也是兩步走:
1. 通過統一下單接口發起請求,獲得mweb_url(支付跳轉url),這個是你接下來進入微信提供的支付頁面的地址;
2. 完成支付流程后,實現后續邏輯。

一)發起統一下單接口

此處請參考【微信支付之公眾號支付】博客里的流程,這里有兩個地方需要注意:
1)本次請求中的參數:交易類型(trade_type)的值是“MWEB”
2)本次返回結果需要得到的是“mweb_url”的值

參考方法(由於上一篇公眾號支付寫的比較詳細,只列出上文沒有細說的方法,值得注意的是這個UnifiedOrder對象里是沒有openid這個字段,api說明里也提到過公眾號支付必填openid,H5支付是不用填寫的,主要是沒有,O(∩_∩)O哈哈~)

 /**
     * 
     * @Description: 微信支付 -統一訂單類型獲得mweb_url
     * @author tianpengw 
     * @param uo
     * @return
     */
    public static String getUnifiedOrderMWebUrl(UnifiedOrder uo){
        String sign = createUnifiedOrderSign(uo);
        uo.setSign(sign);
        String xml = XMLBeanUtils.objectToXMLStr(uo);
        log.info("H5支付統一訂單請求參數:"+xml);
        String res = HttpHelper.httpsRequest(unifiedUrl,"POST",xml);
        log.info("H5支付統一訂單返回結果:"+res);
        Map<String, String> responseMap = XMLBeanUtils.readStringXmlOut(res);
        return responseMap.get("mweb_url");
    }

相關的工具類不在贅述,參考上文公眾號支付博客

通過此方法得到MWebUrl結果后,送到前端,通過window.location.href跳轉即可完成H5支付流程,值得注意的是,H5支付掃尾比公眾號支付要麻煩:

【官方文檔】
一、回調頁面

正常流程用戶支付完成后會返回至發起支付的頁面,如需返回至指定頁面,則可以在MWEB_URL后拼接上redirect_url參數,來指定回調頁面。

如,您希望用戶支付完成后跳轉至https://www.wechatpay.com.cn,則可以做如下處理:

假設您通過統一下單接口獲到的MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096 

則拼接后的地址為MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cn

    注意:
    1.需對redirect_url進行urlencode處理
    2.由於設置redirect_url后,回跳指定頁面的操作可能發生在:1,微信支付中間頁調起微信收銀台后超過5秒 2,用戶點擊“取消支付“或支付完成后點“完成”按鈕。因此無法保證頁面回跳時,支付流程已結束,所以商戶設置的redirect_url地址不能自動執行查單操作,應讓用戶去點擊按鈕觸發查單操作。回跳頁面展示效果可參考下圖

官方文檔提到兩個關鍵地方,第一點是用戶可通過拼接redirect_url來指引微信處理后的跳轉動向,這個地址需要urlencode處理,第二點是不管什么結果最終結束后微信都會調用這個redirect_url地址,這些交給后端完成,讓后端跳轉 微信h5支付的鏈接,  前端  就一個下單接口, 其他事交給后端,

 

 

這邊特別注意這塊代碼(紅色的)  必須寫,  不然會報錯,  后端代碼也需要改,參考下面鏈接

ajax不支持  重定向 跳轉!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  參考鏈接 ajax不支持重定向!!https://www.cnblogs.com/ynxrsoft/p/9408253.html

前端部分代碼如下:

var jqxhr $.ajaxSetup({ complete: function () { if ("REDIRECT" == jqxhr.getResponseHeader("REDIRECT")) { //若HEADER中含有REDIRECT說明后端想重定向, var win = window; while (win != win.top) { win = win.top; } win.location.href = jqxhr.getResponseHeader("CONTENTPATH");//將后端重定向的地址取出來,使用win.location.href去實現重定向的要求 } } }); jqxhr = $.ajax({
                    url: config.api_buy,
                    type:"post",
                    async:true,
                    headers: {
                        'Content-Type':'application/json;charset=UTF-8'
                    },
                    data: JSON.stringify(obj),
                    success:res=>{
                        console.log('0元下單',res)
                        if(res.error == "00"){
                            that.$toast.success('領取成功')
                            that.flag = 1
                            // window.location.href = res.mweb_url+'&redirect_url='+'http://127.0.0.1:5500/Page-YongAnXing/localLife.html?aa='+res.mweb_url
                        }else{
                            that.$toast.fail(res.msg)
                        }
                    }
                })

重定向 頁面自己寫了,  到時候調用  訂單查詢看看是否支付成功   或者支付失敗  取消支付   在對其 進行跳轉

最后貼出服務端方法:

/**
     * H5支付
     * @param req
     * @param ids
     * @param addrId
     * @param orderRemark
     * @return 
     * @throws UnsupportedEncodingException 
     */
    @RequestMapping(value = "gotoJSPayH5.json")
    @ResponseBody
    public Response gotoJSPayH5(HttpServletRequest req, @RequestBody PhoneBean pb) throws UnsupportedEncodingException{
        log.info("進入H5支付:" + pb.getOrderId());
        Response resp = new Response();
        if(!MyStringUtils.isEmpty(pb.getOrderId())){
            Order order = orderService.findOrderForPayH5(pb.getOrderId());
            if(null != order){
                Date endDate = MyDateUtil.parseDate(MyDateUtil.get30Minute(order.getOrderCreateTime()),MyDateUtil.DATETIME);
                if(MyConstants.order_need_pay == order.getOrderStatus() && new Date().before(endDate)){
                    UnifiedOrder uo = new UnifiedOrder();
                    uo.setSpbill_create_ip(HttpHelper.getClientIP(req));
                    uo.setTrade_type(WechatPayUtil.tradeTypeH5);
                    uo.setBody(MyConstants.project_title+"-商品支付");
                    uo.setOut_trade_no(order.getOrderId());
                    //測試環境
                    if("test".equals(getDicValueByAlias("environment"))){
                        uo.setTotal_fee(1);//測試使用單位分
                    }else{
                        uo.setTotal_fee(order.getOrderTotalPrice().multiply(new BigDecimal(100)).intValue());//單位分
                    }
                    String mwebUrl = WechatPayUtil.getUnifiedOrderMWebUrl(uo);
                    if(!MyStringUtils.isEmpty(mwebUrl)){
                        //增加支付記錄
                        WechatPay wp = new WechatPay();
                        wp.setPayId(RandomUtils.g());
                        wp.setPayOrderId(order.getOrderId());
                        //測試環境
                        if("test".equals(getDicValueByAlias("environment"))){
                            wp.setPayAmount(new BigDecimal(0.01));//測試使用
                        }else{
                            wp.setPayAmount(order.getOrderTotalPrice());
                        }
                        wp.setPayReturnUrl(mwebUrl);
                        wp.setPayType(WechatPayUtil.tradeTypeH5);
                        wp.setPayStatus(MyConstants.pay_status_ing);
                        wp.setPayNonceStr(uo.getNonce_str());
                        wpService.insertWechatPay(wp);
                        //拼接實現地址:跳轉支付完成頁面
                        resp.setData(mwebUrl+ "&redirect_url=" +URLEncoder.encode(MyConstants.product_address 
                                + "/phone/payComplete.do?orderId=" + order.getOrderId() + "&tradeType=" + WechatPayUtil.tradeTypeH5,"utf-8"));
                        resp.setErrCode(ErrorCode.err_code_success);
                    }

                }else if(MyConstants.order_has_pay == order.getOrderStatus()){
                    resp.setErrCode(ErrorCode.err_code_fail);
                    resp.setErrMsg("訂單已完成支付,請勿重復支付!");
                }else{
                    resp.setErrCode(ErrorCode.err_code_fail);
                    resp.setErrMsg("訂單已失效,請重新選購商品!");
                }
            }
        }else{
            resp.setErrCode(ErrorCode.err_code_fail);
            resp.setErrMsg("訂單無效,支付異常!");
        }
        return resp;
    }

這里有一些常用的方法就不再貼出了,簡單描述下:
MyStringUtils:字符串處理工具類isEmpty() 非空判斷方法;
MyDateUtil:日期解析工具類 parseDate()字符串轉日期方法;

至此H5支付的主要流程就結束了,我的代碼是兩種支付的結合,有單獨需求的可以分開,請繼續關注【微信開發之自定義分享】,下文中我將把我自己總結jar包和源碼都分享出來,供大家參考學習

 

 

 

參考地址:  https://blog.csdn.net/niaoer2010/article/details/78229247?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.edu_weight


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM