APP內嵌網頁使用微信或支付寶的H5支付


微信和支付寶的H5支付下單成功后都會返回一個跳轉支付的url連接,通過這個連接可以拉起微信或支付寶進行支付操作。

如果直接訪問,支付寶會有一個中間的頁面,而微信有個麻煩的refresh驗證問題;那么是否可以跳過這個步驟直接將微信支付寶拉起進行支付呢?

網上大部分的教程都是讓做安卓和IOS的自己去攔截微信和支付寶的地址進行處理。但是對這種內嵌網頁,前端的同學就非常不好操作了;那么這個活就需要后端的同學辛苦哈來解決了(ง •_•)ง。

首先需要知道的是每一個手機APP都有一個唯一的URL Scheme地址,訪問這個地址即可將對應的APP打開。
基於這個原理,那么微信和支付寶的支付最終肯定也是基於此來實現將其APP拉起然后讓用戶進行支付的。
因此讓后端對支付地址處理下,直接返回可以拉起微信和支付寶的支付URL Scheme;這樣就可以直接用了,微信的refresh驗證也可以跳過了。

首先是微信H5支付

通過程序直接請求微信H5支付下單返回的支付鏈接,返回如下(下面是返回的部分html代碼):

在Html代碼中有以weixin://開頭的鏈接;而weixin://正好是微信的URL Scheme,這個就是之后調用微信支付的鏈接,在手機瀏覽器上打開這個鏈接正好可以調起微信支付進行支付。
說明微信在這個頁面上並沒有做其他的騷操作,那些Referer攔截只是一些簡單的前台攔截。那么我們通過后端程序直接去請求微信返回H5支付鏈接,然后將返回的HTML中的微信支付URL Scheme提取出來直接返回給前端即可。

下面是Java示例代碼

    HttpHeaders headers = new HttpHeaders();
    headers.add("Host", "wx.tenpay.com");
    headers.add("Accept-Language", "en, zh-CN; q=0.8,zh; q=0.6,en-US; q=0.4");
    headers.add("Accept", "text/html,application/xhtml+xml, application/xml ; g=0. 9 ,image/webp,*/* ; q=0.8");
    headers.add("Upgrade-Insecure-Requests", "1");
    // 這個地方寫你自己在微信支付后台配置的安全域名
    headers.add("Referer", "https://www.baidu.com");
    HttpEntity<String> httpEntity = new HttpEntity<>(headers);

    try{
        // 使用spring的 RestTemplate; mweb_url是微信的H5支付鏈接
        ResponseEntity<String> exchange = this.restTemplate.exchange(mweb_url, HttpMethod.GET, httpEntity, String.class);
        String body = exchange.getBody();
        if(StringUtils.isBlank(body)){
            System.out.println("請求無響應");
            return url;
        }
        // 通過正則表達式提取需要的字符串
        String pattern= "\"weixin(.*?)\"";
        Pattern p = Pattern.compile(pattern);
        Matcher matcher = p.matcher(body);
        if(matcher.find()){
            String pullUrl = matcher.group();
            return pullUrl.substring(1, pullUrl.length()-1);
        }
    }catch (Exception e){
        System.out.println("請求異常");
    }
    return url;

需要注意的是使用這種方式就不要再將會回跳地址傳入了,同時需要自己做個是否支付成功的判斷。

支付寶H5支付

基於剛才微信的思路,使用同樣的方式來處理支付寶的。支付寶返回的HTML內容中沒有現成的支付寶支付的URL Scheme。通過調試和HTML代碼分析,提取出其支付URL Scheme如下:

# 安卓的(實際測試中,蘋果手機使用這個也可以拉起支付寶)
alipays://platformapi/startApp?appId=102564&orderSuffix=' + o.android + '#Intent;scheme=alipays;package=com.eg.android.AlipayGphone;end
# 蘋果的
alipay://alipayclient/?o.ios

其中o.ios和o.android的內容是使用url encoder編碼了的;其中蘋果的內容是如下的JSON串:

{
  "requestType": "SafePay",
  "fromAppUrlScheme": "alipays",
  "dataString": "h5_route_token=\"FPwoiehfPAWuiofw\"&is_h5_route=\"true\"&need_invoke_app=\"true\""
}

安卓的只有一個dataString的值。通過字段的值對比h5_route_token其值就是HTML中的session的值;在返回的HTML代碼中有如下代碼:

var inData = { "requestType": "SafePay", "fromAppUrlScheme": "alipays", "dataString": "h5_route_token=\"FPwoiehfPAWuiofw\"&is_h5_route=\"true\"&need_invoke_app=\"true\"" };

這個就是上面需要的內容,同樣通過正則表達式將內容提取出來。

下面是Java示例代碼:

HttpGet httpGet = new HttpGet(h5Url);
httpGet.setConfig(RequestConfig.custom()
        .setConnectTimeout(HttpConstants.CONNECT_TIMEOUT)
        .setConnectionRequestTimeout(HttpConstants.CONNECTION_REQUEST_TIMEOUT)
        .setSocketTimeout(HttpConstants.SOCKET_TIMEOUT).build());

CloseableHttpClient httpClient = HttpClientBuilder.create().build();
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
    if(response.getEntity()!=null){
        String body = EntityUtils.toString(response.getEntity(), "UTF-8");

        // 通過正則表達式提取需要的字符串;也可以直接提取session的值 `pattern = "'session':(.*)'";`
        String pattern= "inData =(.*)";
        Pattern p = Pattern.compile(pattern);
        Matcher matcher = p.matcher(body);
        if(matcher.find()){
            String pullUrl = matcher.group();
            if(pullUrl.length()>9){
                pullUrl = pullUrl.substring(9, pullUrl.length()-1);
                if(isAndroid){
                    JSONObject params = JSONObject.parseObject(pullUrl);
                    if(params.getString("dataString")!=null){
                        pullUrl = params.getString("dataString");
                        // 安卓
                        return String.format("alipays://platformapi/startApp?appId=549984&orderSuffix=%s#Intent;scheme=alipays;package=com.eg.android.AlipayGphone;end", URLEncoder.encode(pullUrl, "utf-8"));
                    }
                }else {
                    // iso
                    return String.format("alipay://alipayclient/?%s", URLEncoder.encode(pullUrl.trim(), "utf-8"));
                }
            }
        }
        System.out.println("請求返回內容:"+ body);
    }else {
        System.out.println("無請求內容返回");
    }
} catch (IOException e) {
    System.out.println("處理異常");
}finally {
    try {
        httpClient.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
return null;

這種方式對原生的APP開發應該也適用,即不使用微信支付寶的APP支付方式,直接使用H5的支付方式,這樣就無需再去對接其APP支付的SDK了。

關注微信訂閱號‘起岸星辰’獲取最新資訊


免責聲明!

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



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