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