Android WebView 調起H5支付,提示商家參數格式有誤

題記
—— 執劍天涯,從你的點滴積累開始,所及之處,必精益求精,即是折騰每一天。

重要消息


1 引言

場景描述:在APP 中使用webView 顯示第三方H5, H5中涉及到微信支付流程,無法正常支付,提示 “商家參數格式有誤,請聯繫商家解決”。

1.1 線索分析

參照微信H5 支付開發官方文檔點擊這裏查看

描述一
微信文檔描述
一般提示出錯,我們可以先去微信商戶管理平臺點擊這裏查看 配製,當然出錯後,也不急着去商戶後臺去查看配製,因爲在開發微信支付功能初期這些都是已經配製好的,當然是在其平臺比如 瀏覽器、Ios UIWebview 等都可以正常的調起支付,那說明在商戶後臺的配製是沒有問題的,不過我們也可以再次去查看一下商戶後臺配製的具體值。

描述二

參照微信H5 支付開發官方文檔常見問題點擊這裏查看

微信支付提示商家參數格式有誤
在網絡發生變動的情況會出現此提示之一
微信支付提示商家參數格式有誤

也有提到 “如果是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 丟失 。

2 關於 Referer 丟失的問題

關於 Referer 丟失的問題 首先 referer 是由客戶端的瀏覽器發送到服務器上,且在客戶端可以通過 document.referrer 來獲取,也就是說referer的發送實際上是一個瀏覽器行爲,發送與否的決定權是在瀏覽器手裏。雖然這樣說,但是HTTP協議對什麼情況下,瀏覽器該發送,什麼情況下不該發送有着嚴格的規定。

2.1 分析 Referer 丟失的幾種情況
  • 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()

2.2 分析一 HTTPS變HTTP

有時候需要在API項目中生成一些URL鏈接返回 但是服務器端已經配置了支持HTTPS,通過HTTPS訪問的時候生成的URL仍然是HTTP

從 HTTPS 站點跳到 HTTP 站點 丟失了 Referer,反過來從HTTP到HTTPS是沒問題的 不會丟失 Referer

2.3 分析二 微信的支付Referer丟失

從前端請求到 API 整個都沒有問題 全部項目已經全線部署了 HTTPS , Referer 信息也有攜帶 然後只有到最後一步微信的支付請求URL的時候 Referer 就丟失了

發佈了354 篇原創文章 · 獲贊 182 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章