【问题标题】:Intercept POST requests in a WebView在 WebView 中拦截 POST 请求
【发布时间】:2012-12-19 14:03:00
【问题描述】:

我正在开发一个过滤请求(带有白名单)并使用自定义 SSLSocketFactory 的 Android 应用程序。为此,我开发了一个自定义的WebViewClient 并覆盖了shouldInterceptRequest 方法。我可以过滤并将我的SocketFactory 与 GET 请求一起使用,但我无法拦截 POST 请求。

那么,有没有办法拦截WebView 中的 POST 请求?

这里是 shouldInterceptRequest 方法的代码:

public final WebResourceResponse shouldInterceptRequest(WebView view, String urlStr) {
    URI uri = URI.create(urlStr);
    String scheme = uri.getScheme();
    // If scheme not http(s), let the default webview manage it
    if(!"http".equals(scheme) && !"https".equals(scheme)) {
        return null;
    }
    URL url = uri.toURL();

    if(doCancelRequest(url)) {
        // Empty response
        Log.d(TAG, "URL filtered: " + url);
        return new WebResourceResponse("text/plain", "UTF-8", new EmptyInputStream());

    } else {
        Log.d(TAG, "URL: " + url);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestProperty("User-Agent", mSettings.getUserAgentString());

        // Configure connections
        configureConnection(conn);

        String mimeType = conn.getContentType();
        String encoding = conn.getContentEncoding();

        if(mimeType != null && mimeType.contains(CONTENT_TYPE_SPLIT)) {
            String[] split = mimeType.split(CONTENT_TYPE_SPLIT);
            mimeType = split[0];

            Matcher matcher = CONTENT_TYPE_PATTERN.matcher(split[1]);
            if(matcher.find()) {
                encoding = matcher.group(1);
            }
        }

        InputStream is = conn.getInputStream();
        return new WebResourceResponse(mimeType, encoding, is);
    }
}

【问题讨论】:

  • 您是否遇到错误,或者它根本不起作用?您也应该发布一些相关代码,例如您覆盖的 shouldInterceptRequest 方法。
  • 不,我没有错误。我在 shouldInterceptRequest 方法的开头记录了 url,我只看到 GET 请求。其他的似乎在 WebView 低级别管理。

标签: android post webview request


【解决方案1】:

几天前我遇到了同样的问题。

所以我建立了一个库来解决它:

https://github.com/KonstantinSchubert/request_data_webviewclient

它是一个带有自定义 WebResourceRequest 的 WebViewClient,其中包含 XMLHttpRequest 请求的 POST/PUT/... 负载。

它只适用于这些 - 不适用于表单和其他类型的请求源。

黑客的工作原理基本上是通过将脚本注入 HTML 来拦截 XMLHttpRequest 调用。它记录 post/put/... 内容并将其发送到android.webkit.JavascriptInterface。在那里,请求被隐藏起来,直到 Android 调用 shouldInterceptRequest 方法...

【讨论】:

  • 非常聪明的破解这个问题。谢谢。转换为使用 Xamarin.Android 并在遇到此问题时节省了时间。
【解决方案2】:

【讨论】:

  • 是的,我在 android bugtracker 中发现了这个问题。但就我而言,我无法将 POST 更改为 GET 请求,因为我不知道我将连接到哪个服务器。例如,我无法连接到 GMail,因为在身份验证期间有一个 POST 请求。
  • 看看这个库:github.com/KonstantinSchubert/request_data_webviewclient我是在遇到类似问题时写的。
【解决方案3】:

我在上面的线程http://code.google.com/p/android/issues/detail?id=9122有我的答案之一

请看comment#31

我看到的解决方案的一些注意事项是:

  1. 依赖于 xmlhttprequest 原型,该原型对不同的 webkits 有不同的实现。
  2. 在 URL 中为发布请求发送数据时出现安全问题。但我想你可以通过某种加密机制来解决这个问题。
  3. 如果您发布大数据,某些浏览器的 URL 长度问题

除此之外,我发现 this github repo 似乎正在以另一种 hacky 方式解决这个问题。我查看了代码,但没有时间实现和测试它。但值得一试。

【讨论】:

    【解决方案4】:

    我发现最简单的方法是使用带有 Javascript 接口的 JQuery Ajax Event Handlers

    您必须设置 Javascript 接口,但一旦您设置了与您感兴趣的处理程序的签名相匹配即可。

    要获取payload,只要找到payload变量名放到界面中即可。

    这里是 Javascript:

     $( document ).ajaxSend(function( event, request, settings ) {
          var eventJSON= JSON.stringify(event);
          var requestJSON = JSON.stringify(request);
          var settingsJSON = JSON.stringify(settings);
          var payloadJSON = JSON.stringify(payload);
    
          myJSInterface.passData(eventJSON,requestJSON,settingsJSON,payloadJSON);       
     });
    

    这是 Kotlin 类

     class yourJSInterface() {
          lateinit var event: String
          lateinit var request: String
          lateinit var settings: String
          lateinit var payload: String
     
          @JavascriptInterface
          fun passData(eventJSON:String, responseJSON:String, settingsJSON:String,payloadJSON:String){
               event = eventJSON
               response= responseJSON
               settings= settingsJSON
               payload= payloadJSON
          }
     }
    

    WebViewClient 的 onPageStarted 覆盖中的注册

     webView.addJavascriptInterface(yourJSInterface,"myJSInterface")
    

    最后在 OnPageFinished override 中将 JS 注入到 WebView 中

     webView.evaluateJavascript("javascript:" + getString(R.string.js_from_above),null)
    

    我在 onPageStarted 中注册了接口,否则 onPageFinished 中的 javascript 文件将无法识别您的接口。

    【讨论】:

      【解决方案5】:

      有一个更简单的解决方案:在ajax调用中通过GET发送参数,并在shouldInterceptRequest中转换为POST

      【讨论】:

        【解决方案6】:

        您可以在提交前获取输入值
        https://github.com/henrychuangtw/WebView-Javascript-Inject

        第 1 步:创建一个由 javascript 调用的类

        class MyJavaScriptInterface
        {
            @JavascriptInterface
            public void processHTML(String html)
            {
                //called by javascript
            }
        }
        


        第二步:注册javascript接口

        webview1.getSettings().setJavaScriptEnabled(true);
        webview1.addJavascriptInterface(new MyJavaScriptInterface(), "MYOBJECT");
        


        第 3 步:将 javascript 注入页面

        webview1.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
        
                StringBuilder sb = new StringBuilder();
                sb.append("document.getElementsByTagName('form')[0].onsubmit = function () {");
                sb.append("var objPWD, objAccount;var str = '';");
                sb.append("var inputs = document.getElementsByTagName('input');");
                sb.append("for (var i = 0; i < inputs.length; i++) {");
                sb.append("if (inputs[i].type.toLowerCase() === 'password') {objPWD = inputs[i];}");
                sb.append("else if (inputs[i].name.toLowerCase() === 'email') {objAccount = inputs[i];}");
                sb.append("}");
                sb.append("if (objAccount != null) {str += objAccount.value;}");
                sb.append("if (objPWD != null) { str += ' , ' + objPWD.value;}");
                sb.append("window.MYOBJECT.processHTML(str);");
                sb.append("return true;");
                sb.append("};");
        
                view.loadUrl("javascript:" + sb.toString());
            }
        
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-03-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-12
          相关资源
          最近更新 更多