题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每⼀天。
主要

精通点的可以查看这里 精述 https://gitbook.cn/gitchat/author/5ae043915efcf9715e37c733
Flutter 从入门实践到开拓一个APP之UI根本篇 视频https://edu.csdn.net/course/detail/25543
flutter从入门 到精通 系列文章https://blog.csdn.net/zl18603543572/article/details/93532582
1 弁言场景描述:在APP 中使⽤webView 显示第三⽅H5, H5中涉及到微信⽀付流程,⽆法正常⽀付,提示 "商家参数格式有误,请联系商家办理"。
参照微信H5 ⽀付开拓官⽅⽂档
https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1
描述⼀⼀般提示出错,我们可以先去微信商户管理平台查看配制,
https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F
当然出错后,也不急着去商户后台去查看配制,由于在开拓微信⽀付功能初期这些都是已经配制好的,当然是在其平台⽐如 浏览器、Ios UIWebview 等都可以正常的调起⽀付,那解释在商户后台的配制是没有问题的,不过我们也可以再次去查看⼀下商户后台配制的详细值。
描述⼆参照微信H5 ⽀付开拓官⽅⽂档常⻅问题
https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4
1 引⾔1.1 线索剖析在⽹络发⽣变动的情形会涌现此提示之⼀
也有提到 "如果是APP⾥调起H5⽀付,须要在webview中⼿动设置referer",详细内容如下
那么到这⾥,我们可以⼿动的在 Android WebView 中添加头 referer ,这个要求头
简⾔之,HTTP Referer是header的⼀部分,当浏览器向web做事器发送要求的时候,⼀般会带上Referer,见告做事器我是从哪个⻚⾯链接过来的,做事器 籍此可以得到⼀些信息⽤于处理。⽐如从我主⻚上链接到⼀个朋友那⾥,他的做事器就能够从HTTP Referer中统计出每天有多少⽤户点击我主⻚上的链接访问他的⽹站。Referer实在该当是英⽂单词Referrer,不过拼错的⼈太多了,以是编写标准的⼈也就将错就错了在安卓WebView中⼿动配制要求头 referer
然后再次使⽤ 安卓 WebView 来加载 H5 项⽬,然后发起微信⽀付,然后发起成功
剖析:当没有在Android WebView 中添加头 referer 要求头,同样的 H5 项⽬,分别在 在 Android WebView 、浏览器、ios UIWebVie 中访问打开,浏览器、ios UIWebVie 中,都可以正常调起⽀付,只有 Android WebView中微信⽀付调起失落败,提示商家参数格式有误
当 在Android WebView 中添加头 referer(这个值对应的微信商户平台后台配制的值) 要求头,再次访问同样的 H5 项⽬,再次调起微信⽀付,成功。
然后使⽤抓包⽅式进⼀步剖析:
在浏览器中对其加载⽹络剖析
然后在 Android WebView 、ios UIWebView 中加载H5 项⽬ 然后对 Android ios中的WebView 配制抓包代替,然后访问 H5 项⽬
得出结论 要求头 referer 并没有丢失,然后进⼀步 抓包剖析得出结论 在 Android ios 中加载 H5 项⽬,要求头 referer配制的信息 与商户管理后台配制的⼀⾄,并没有丢失或者是配制缺点(当然在ios UIWebView 能⽀付成功也可以解释)
那么问题来了,在Android WebView 中 如果不配制 要求头 referer 调起失落败,我们须要找出缘故原由
在 Android WebView 中 没有设置 referer 要求 header 前
mWebView.setWebViewClient(new WebViewClient() { @Override @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { //利用WebView加载显示url view.loadUrl(url); //返回true return true; } // Handle API 21+ @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { ///获取要求uir String url = request.getUrl().toString(); ///获取RequestHeader中的所有 key value Map<String, String> lRequestHeaders = request.getRequestHeaders(); for (Map.Entry<String, String> lStringStringEntry : lRequestHeaders.entrySet()) { Log.d("测试header", lStringStringEntry.getKey() + " " + lStringStringEntry.getValue()); } return super.shouldInterceptRequest(view, request); } });
然后 在掌握台中查看 调起⽀付那⼀下要求的信息
对应的抓包⼯具中数据
剖析数据 得出: 发起微信⽀付时 referer 丢失
https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id= 后⾯省略
然后在 Android 中⼿动配制 referer 后,H5 微信⽀付调起成功,抓包数据
mWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { try { if (url.startsWith("http:") || url.startsWith("https:")) { HashMap<String, String> lStringStringHashMap = new HashMap<>(); if (!TextUtils.isEmpty(mReffer)) { lStringStringHashMap.put("referer", mReffer); view.loadUrl(url, lStringStringHashMap); } else { view.loadUrl(url, lStringStringHashMap); } } else { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); } return true; } catch (Exception e) { } //利用WebView加载显示url view.loadUrl(url); //返回true return true; } @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { handler.proceed(); } // Handle API 21+ @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { ///获取要求uir String url = request.getUrl().toString(); ///获取RequestHeader中的所有 key value Map<String, String> lRequestHeaders = request.getRequestHeaders(); Log.e("测试URI",url); for (Map.Entry<String, String> lStringStringEntry : lRequestHeaders.entrySet()) { Log.d("测试header", lStringStringEntry.getKey() + " " + lStringStringEntry.getValue()); } if (lRequestHeaders.containsKey("Referer")) { mReffer = lRequestHeaders.get("Referer"); } return super.shouldInterceptRequest(view, request); } });
结论来了: 在调微信 H5 ⽀付
https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb
要求头 referer 丢失 。
关于 Referer 丢失的问题⾸先 referer 是由客户真个浏览器发送到做事器上,且在客户端可以通过 document.referrer 来获取,也便是说referer的发送实际上是⼀个浏览器⾏为,发送与否的决定权是在浏览器⼿⾥。虽然这样说,但是HTTP协议对什么情形下,浏览器该发送,什么情形下不该发送有着严格的规定。
1.当⽹站使⽤refresh字段进⾏跳转的时候,⼤多数浏览器不发送referer2.从⽤户从⼀个HTTPS的⽹站点击链接到另⼀个HTTP的⽹站时,不发送referer3.html5中,a标签的rel = "noreferrer", 可以让浏览器不发送referer4.使⽤Data URI scheme链接的,浏览器也不发送referer5.使⽤Content Security Policy, 也可以让浏览器不发送referer6.在html头部中使⽤meta标签来掌握不让浏览器发送referer7.在发起⽀付的时候 android WebView 过滤了 referer,办理⽅式便是
///在H5项目中发起支付时 https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb///一样平常可利用 但会导致 在 android WebView 中丢失referer<script type="text/javascript">window.location.href="https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?支付信息";</script>
下⾯两种⽅式 android WebView 中不会丢失referer
<body> <form name="form"> </form> </body><scrip> document.form.method= "post"; document.form.action= "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?支付信息 "; document.form.submit(); </scrip>
jQuery动态创建form表单提交
2.2 剖析⼀ HTTPS变HTTP
var action='https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?支付信息 ' var form = $("<form></form>") form.attr('action', action) form.attr('method', 'post') //追加到body,不显示,然后提交 form.appendTo("body") form.css('display', 'none') form.submit()
有时候须要在API项⽬中⽣成⼀些URL链接返回 但是做事器端已经配置了⽀持HTTPS,通过HTTPS访问的时候⽣成的URL仍旧是HTTP
从 HTTPS 站点跳到 HTTP 站点 丢失了 Referer,反过来从HTTP到HTTPS是没问题的 不会丢失 Referer
从前端要求到 API 全体都没有问题 全部项⽬已经全线支配了 HTTPS , Referer 信息也有携带 然后只有到末了⼀步微信的⽀付要求URL的时候 Referer 就丢失了