題記 —— 執劍天涯,從你的點滴積累開始,所及之處,必精益求精,便是折騰每一天。javascript
重要消息php
場景描述:在APP 中使用webView 顯示第三方H5, H5中涉及到微信支付流程,沒法正常支付,提示 「商家參數格式有誤,請聯繫商家解決」。css
參照微信H5 支付開發官方文檔點擊這裏查看html
描述一 前端
描述二html5
參照微信H5 支付開發官方文檔常見問題點擊這裏查看java
也有提到 「若是是APP裏調起H5支付,須要在webview中手動設置referer」,具體內容以下 android
簡言之,HTTP Referer是header的一部分,當瀏覽器向web服務器發送請求的時候,通常會帶上Referer,告訴服務器我是從哪一個頁面連接過來的,服務器 籍此能夠得到一些信息用於處理。好比從我主頁上連接到一個朋友那裏,他的服務器就可以從HTTP Referer中統計出天天有多少用戶點擊我主頁上的連接訪問他的網站。ios
Referer其實應該是英文單詞Referrer,不過拼錯的人太多了,因此編寫標準的人也就將錯就錯了git
在安卓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字段進行跳轉的時候,大多數瀏覽器不發送referer
2.從用戶從一個HTTPS的網站點擊連接到另外一個HTTP的網站時,不發送referer
3.html5中,a標籤的rel = 「noreferrer」, 可讓瀏覽器不發送referer
4.使用Data URI scheme連接的,瀏覽器也不發送referer
5.使用Content Security Policy, 也可讓瀏覽器不發送referer
6.在html頭部中使用meta標籤來控制不讓瀏覽器發送referer
7.在發起支付的時候 android WebView 過濾了 referer,解決方式就是 android WebView 中手動設置 refere 或者修改 H5項目中的微信支付發起的方式。
///在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表單提交
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 就丟失了