zoukankan      html  css  js  c++  java
  • 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了。

    关注微信订阅号‘起岸星辰’获取最新资讯

  • 相关阅读:
    协方差矩阵
    VS2010+C#+EmguCV 配置详解
    OpenCv,EmguCv及.net之间的互动(The Interaction of OpenCv, EmguCv AND .net)
    EmguCV学习 与opencv的区别和联系
    redis新手入门,摸不着头脑可以看看<二>
    java常用工具类[待补充]
    redis新手入门,摸不着头脑可以看看<一>
    用java代码发送http请求
    Date和long类型互转
    WEB-INF目录下文件复制的几种方式
  • 原文地址:https://www.cnblogs.com/vchar/p/13733027.html
Copyright © 2011-2022 走看看