Android 在WebView中拦截POST请求

Android 在WebView中拦截POST请求,android,post,webview,request,Android,Post,Webview,Request,我正在开发一个Android应用程序来过滤请求(带有一个白名单),并使用一个定制的SSLSocketFactory。为此,我开发了一个定制的WebViewClient,并重写了shouldInterceptRequest方法。我可以对GET请求过滤并使用我的SocketFactory,但我无法截获POST请求 那么,有没有办法在WebView中拦截POST请求呢 以下是shoulInterceptRequest方法的代码: public final WebResourceResponse sho

我正在开发一个Android应用程序来过滤请求(带有一个白名单),并使用一个定制的
SSLSocketFactory
。为此,我开发了一个定制的
WebViewClient
,并重写了
shouldInterceptRequest
方法。我可以对GET请求过滤并使用我的
SocketFactory
,但我无法截获POST请求

那么,有没有办法在
WebView
中拦截POST请求呢

以下是shoulInterceptRequest方法的代码:

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);
    }
}

使用GET而不是POST

已知问题:

这里也有人回答:

我在上面的帖子中有一个答案

请看

我看到的解决方案的一些警告是:

  • 将依赖关系放在xmlhttprequest原型上,该原型对不同的WebKit具有不同的实现
  • 在URL中为post请求发送数据时存在安全问题。但我想你可以通过某种加密机制来解决这个问题
  • 如果要发布大数据,某些浏览器的URL长度问题

  • 除此之外,我发现它似乎以另一种骇人的方式解决了这个问题。我研究了代码,但没有时间实现和测试它。但是值得一试。

    您可以在提交之前获得输入值

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

    class MyJavaScriptInterface
    {
        @JavascriptInterface
        public void processHTML(String html)
        {
            //called by javascript
        }
    }
    
    webview1.getSettings().setJavaScriptEnabled(true);
    webview1.addJavascriptInterface(new MyJavaScriptInterface(), "MYOBJECT");
    

    步骤2:注册javascript接口

    class MyJavaScriptInterface
    {
        @JavascriptInterface
        public void processHTML(String html)
        {
            //called by 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());
        }
    
    });
    
    webview1.setWebViewClient(新的WebViewClient(){
    @凌驾
    公共void onPageFinished(WebView视图,字符串url){
    super.onPageFinished(视图、url);
    StringBuilder sb=新的StringBuilder();
    append(“document.getElementsByTagName('form')[0].onsubmit=function(){”);
    sb.追加(“var objPWD,objAccount;var str=”;”;
    sb.append(“var inputs=document.getElementsByTagName('input');”;
    sb.append(“for(vari=0;i
    几天前我也面临同样的问题

    所以我建立了一个库来解决这个问题:

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

    但它只适用于这些应用程序,而不适用于表单和其他类型的请求源


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

    我发现最简单的方法就是使用Javascript接口

    您必须设置Javascript接口,但一旦设置完毕,只需让它与您感兴趣的处理程序的签名匹配即可

    要获取有效负载,只需找到有效负载变量名并将其放入接口中

    下面是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);       
     });
    
    这是科特林班

     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
          }
     }
    
    onPageStarted override for WebViewClient中的注册已启动

     webView.addJavascriptInterface(yourJSInterface,"myJSInterface")
    
    最后,将JS注入到OnPageFinished覆盖中的WebView中

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

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

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

    您是否收到错误,或者根本不起作用?你应该发布一些相关的代码,比如你被重写的
    shouldInterceptRequest
    方法。不,我没有错误。我在shoulInterceptRequest方法的开始处记录url,只看到GET请求。其他的似乎是在WebView低层管理的。是的,我在android bugtracker中发现了这个问题。但在我的情况下,我无法将POST更改为GET请求,因为我不知道将连接到哪个服务器。例如,我无法连接到GMail,因为在身份验证过程中有一个POST请求。看看这个库:我在遇到类似问题时写的。这个问题非常聪明。谢谢转换为与Xamarin.Android一起工作,并在面临此问题时节省了时间。