APP內(nèi)嵌網(wǎng)頁使用微信或支付寶的H5支付

APP內(nèi)嵌網(wǎng)頁使用微信或支付寶的H5支付

微信和支付寶的H5支付下單成功后都會(huì)返回一個(gè)跳轉(zhuǎn)支付的url連接呻疹,通過這個(gè)連接可以拉起微信或支付寶進(jìn)行支付操作。

如果直接訪問柏靶,支付寶會(huì)有一個(gè)中間的頁面,而微信有個(gè)麻煩的refresh驗(yàn)證問題;那么是否可以跳過這個(gè)步驟直接將微信支付寶拉起進(jìn)行支付呢袁余?

網(wǎng)上大部分的教程都是讓做安卓和IOS的自己去攔截微信和支付寶的地址進(jìn)行處理。但是對(duì)這種內(nèi)嵌網(wǎng)頁咱揍,特別是那種直接通過前端HTML代碼生成多端的情況颖榜,前端的同學(xué)就非常不好操作了;那么這個(gè)活就需要后端的同學(xué)辛苦哈來解決了(? ?_?)?煤裙。

首先需要知道的是每一個(gè)手機(jī)APP都有一個(gè)唯一的URL Scheme地址掩完,訪問這個(gè)地址即可將對(duì)應(yīng)的APP打開。
基于這個(gè)原理硼砰,那么微信和支付寶的支付最終肯定也是基于此來實(shí)現(xiàn)將其APP拉起然后讓用戶進(jìn)行支付的且蓬。
因此讓后端對(duì)支付地址處理下,直接返回可以拉起微信和支付寶的支付URL Scheme题翰;這樣就可以直接用了恶阴,微信的refresh驗(yàn)證也可以跳過了。

首先是微信H5支付

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

微信支付.jpg

在Html代碼中有以weixin://開頭的鏈接存淫;而weixin://正好是微信的URL Scheme,這個(gè)就是之后調(diào)用微信支付的鏈接沼填,在手機(jī)瀏覽器上打開這個(gè)鏈接正好可以調(diào)起微信支付進(jìn)行支付桅咆。
說明微信在這個(gè)頁面上并沒有做其他的騷操作,那些Referer攔截只是一些簡單的前臺(tái)攔截坞笙。那么我們通過后端程序直接去請(qǐng)求微信返回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");
    // 這個(gè)地方寫你自己在微信支付后臺(tái)配置的安全域名
    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("請(qǐng)求無響應(yīng)");
            return url;
        }
        // 通過正則表達(dá)式提取需要的字符串
        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("請(qǐng)求異常");
    }
    return url;

需要注意的是使用這種方式就不要再將回跳地址傳入了,同時(shí)需要自己做個(gè)是否支付成功的判斷梯澜;也就是說在支付成功后我們的頁面是不會(huì)自動(dòng)回跳的寞冯,因此需要讓前端的同學(xué)辛苦處理哈;比如弄個(gè)支付確認(rèn)彈窗讓用戶主動(dòng)點(diǎn)擊,或者是定期去輪詢幾次訂單狀態(tài)吮龄,同時(shí)如果不條支付中間頁那么最好把支付按鈕暫時(shí)禁用了俭茧,免得由于網(wǎng)絡(luò)延遲這些問題導(dǎo)致重復(fù)支付的問題。

其實(shí)去查看微信支付寶的HTML頁面漓帚,你會(huì)發(fā)現(xiàn)它們的就是通過簡單的js來直接跳轉(zhuǎn)的

支付寶H5支付

基于剛才微信的思路母债,使用同樣的方式來處理支付寶的。支付寶返回的HTML內(nèi)容中沒有現(xiàn)成的支付寶支付的URL Scheme尝抖。通過調(diào)試和HTML代碼分析毡们,提取出其支付URL Scheme如下:

# 安卓的(實(shí)際測試中,蘋果手機(jī)使用這個(gè)也可以拉起支付寶昧辽,可以直接使用一個(gè))
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的內(nèi)容是使用url encoder編碼了的衙熔;其中蘋果的內(nèi)容是如下的JSON串:

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

安卓的只有一個(gè)dataString的值。通過字段的值對(duì)比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\"" };

這個(gè)就是上面需要的內(nèi)容青责,同樣通過正則表達(dá)式將inData的值提取出來,然后手動(dòng)來拼接這個(gè)支付的URL Scheme取具。

下面是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");

        // 通過正則表達(dá)式提取需要的字符串脖隶;也可以直接提取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);
                // 這個(gè)isAndroid值是讓前端同學(xué)傳入的,如果不想?yún)^(qū)分可以直接就用安卓的這個(gè)支付鏈接暇检;因?yàn)樘O果端的用這個(gè)鏈接也可以拉起支付寶支付
                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("請(qǐng)求返回內(nèi)容:"+ body);
    }else {
        System.out.println("無請(qǐng)求內(nèi)容返回");
    }
} catch (IOException e) {
    System.out.println("處理異常");
}finally {
    try {
        httpClient.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
return null;

這種方式對(duì)原生的APP開發(fā)應(yīng)該也適用产阱,即不使用微信支付寶的APP支付方式,直接使用H5的支付方式块仆,這樣就無需再去對(duì)接其APP支付的SDK了构蹬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悔据,隨后出現(xiàn)的幾起案子庄敛,更是在濱河造成了極大的恐慌,老刑警劉巖科汗,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藻烤,死亡現(xiàn)場離奇詭異,居然都是意外死亡头滔,警方通過查閱死者的電腦和手機(jī)怖亭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坤检,“玉大人兴猩,你說我怎么就攤上這事≡缧” “怎么了倾芝?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵讨勤,是天一觀的道長。 經(jīng)常有香客問我蛀醉,道長悬襟,這世上最難降的妖魔是什么衅码? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任拯刁,我火速辦了婚禮,結(jié)果婚禮上逝段,老公的妹妹穿的比我還像新娘垛玻。我一直安慰自己,他們只是感情好奶躯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布帚桩。 她就那樣靜靜地躺著,像睡著了一般嘹黔。 火紅的嫁衣襯著肌膚如雪账嚎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天儡蔓,我揣著相機(jī)與錄音郭蕉,去河邊找鬼。 笑死喂江,一個(gè)胖子當(dāng)著我的面吹牛召锈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播获询,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼涨岁,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了吉嚣?” 一聲冷哼從身側(cè)響起梢薪,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尝哆,沒想到半個(gè)月后秉撇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡较解,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年畜疾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片印衔。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啡捶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奸焙,到底是詐尸還是另有隱情瞎暑,我是刑警寧澤彤敛,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站了赌,受9級(jí)特大地震影響墨榄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜勿她,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一袄秩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逢并,春花似錦之剧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至玻蝌,卻和暖如春蟹肘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俯树。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國打工帘腹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人聘萨。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓竹椒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親米辐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胸完,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355