简体   繁体   English

向WebView资源请求添加自定义标头 - android

[英]Add custom headers to WebView resource requests - android

I need to add custom headers to EVERY request coming from the WebView. 我需要为来自WebView的每个请求添加自定义标头。 I know loadURL has the parameter for extraHeaders , but those are only applied to the initial request. 我知道loadURL具有extraHeaders的参数,但这些参数仅适用于初始请求。 All subsequent requests do not contain the headers. 所有后续请求都不包含标头。 I have looked at all overrides in WebViewClient , but nothing allows for adding headers to resource requests - onLoadResource(WebView view, String url) . 我已经查看了WebViewClient中的所有覆盖,但没有任何内容允许向资源请求添加标头 - onLoadResource(WebView view, String url) Any help would be wonderful. 任何帮助都会很精彩。

Thanks, Ray 谢谢,雷

Try 尝试

loadUrl(String url, Map<String, String> extraHeaders)

For adding headers to resources loading requests, make custom WebViewClient and override: 要将标头添加到资源加载请求,请创建自定义WebViewClient并覆盖:

API 24+:
WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
or
WebResourceResponse shouldInterceptRequest(WebView view, String url)

You will need to intercept each request using WebViewClient.shouldInterceptRequest 您需要使用WebViewClient.shouldInterceptRequest拦截每个请求

With each interception, you will need to take the url, make this request yourself, and return the content stream: 每次拦截时,您需要获取网址,自己发出此请求,然后返回内容流:

WebViewClient wvc = new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

        try {
            DefaultHttpClient client = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);
            httpGet.setHeader("MY-CUSTOM-HEADER", "header value");
            httpGet.setHeader(HttpHeaders.USER_AGENT, "custom user-agent");
            HttpResponse httpReponse = client.execute(httpGet);

            Header contentType = httpReponse.getEntity().getContentType();
            Header encoding = httpReponse.getEntity().getContentEncoding();
            InputStream responseInputStream = httpReponse.getEntity().getContent();

            String contentTypeValue = null;
            String encodingValue = null;
            if (contentType != null) {
                contentTypeValue = contentType.getValue();
            }
            if (encoding != null) {
                encodingValue = encoding.getValue();
            }
            return new WebResourceResponse(contentTypeValue, encodingValue, responseInputStream);
        } catch (ClientProtocolException e) {
            //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        } catch (IOException e) {
             //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        }
    }
}

Webview wv = new WebView(this);
wv.setWebViewClient(wvc);

If your minimum API target is level 21 , you can use the new shouldInterceptRequest which gives you additional request information (such as headers) instead of just the URL. 如果您的最低API目标是21级 ,则可以使用新的shouldInterceptRequest ,它会为您提供其他请求信息(例如标题),而不仅仅是URL。

Maybe my response quite late, but it covers API below and above 21 level. 也许我的反应很晚,但它涵盖了API 以下和21级以上

To add headers we should intercept every request and create new one with required headers. 要添加标头,我们应该拦截每个请求并使用所需的标头创建新的 请求

So we need to override shouldInterceptRequest method called in both cases: 1. for API until level 21; 因此我们需要覆盖在两种情况下调用的shouldInterceptRequest方法:1。用于API直到21级; 2. for API level 21+ 2.对于API级别21+

    webView.setWebViewClient(new WebViewClient() {

        // Handle API until level 21
        @SuppressWarnings("deprecation")
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

            return getNewResponse(url);
        }

        // Handle API 21+
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

            String url = request.getUrl().toString();

            return getNewResponse(url);
        }

        private WebResourceResponse getNewResponse(String url) {

            try {
                OkHttpClient httpClient = new OkHttpClient();

                Request request = new Request.Builder()
                        .url(url.trim())
                        .addHeader("Authorization", "YOU_AUTH_KEY") // Example header
                        .addHeader("api-key", "YOUR_API_KEY") // Example header
                        .build();

                Response response = httpClient.newCall(request).execute();

                return new WebResourceResponse(
                        null,
                        response.header("content-encoding", "utf-8"),
                        response.body().byteStream()
                );

            } catch (Exception e) {
                return null;
            }

        }
   });

If response type should be processed you could change 如果应该处理响应类型,您可以更改

        return new WebResourceResponse(
                null, // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

to

        return new WebResourceResponse(
                getMimeType(url), // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

and add method 并添加方法

        private String getMimeType(String url) {
            String type = null;
            String extension = MimeTypeMap.getFileExtensionFromUrl(url);

            if (extension != null) {

                switch (extension) {
                    case "js":
                        return "text/javascript";
                    case "woff":
                        return "application/font-woff";
                    case "woff2":
                        return "application/font-woff2";
                    case "ttf":
                        return "application/x-font-ttf";
                    case "eot":
                        return "application/vnd.ms-fontobject";
                    case "svg":
                        return "image/svg+xml";
                }

                type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            }

            return type;
        }

As mentioned before, you can do this: 如前所述,您可以这样做:

 WebView  host = (WebView)this.findViewById(R.id.webView);
 String url = "<yoururladdress>";

 Map <String, String> extraHeaders = new HashMap<String, String>();
 extraHeaders.put("Authorization","Bearer"); 
 host.loadUrl(url,extraHeaders);

I tested this and on with a MVC Controller that I extended the Authorize Attribute to inspect the header and the header is there. 我测试了这个,并使用MVC控制器,我扩展了授权属性以检查标头,标头就在那里。

This works for me: 这对我有用:

  1. First you need to create method, which will be returns your headers you want to add to request: 首先,您需要创建方法,该方法将返回您要添加到请求的标头:

     private Map<String, String> getCustomHeaders() { Map<String, String> headers = new HashMap<>(); headers.put("YOURHEADER", "VALUE"); return headers; } 
  2. Second you need to create WebViewClient: 其次,您需要创建WebViewClient:

     private WebViewClient getWebViewClient() { return new WebViewClient() { @Override @TargetApi(Build.VERSION_CODES.LOLLIPOP) public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { view.loadUrl(request.getUrl().toString(), getCustomHeaders()); return true; } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url, getCustomHeaders()); return true; } }; } 
  3. Add WebViewClient to your WebView: 将WebViewClient添加到WebView:

     webView.setWebViewClient(getWebViewClient()); 

Hope this helps. 希望这可以帮助。

You should be able to control all your headers by skipping loadUrl and writing your own loadPage using Java's HttpURLConnection. 您应该能够通过跳过loadUrl并使用Java的HttpURLConnection编写自己的loadPage来控制所有头文件。 Then use the webview's loadData to display the response. 然后使用webview的loadData显示响应。

There is no access to the headers which Google provides. 无法访问Google提供的标头。 They are in a JNI call, deep in the WebView source. 它们位于WebView源代码深处的JNI调用中。

This worked for me. 这对我有用。 Create WebViewClient like this below and set the webclient to your webview. 像下面这样创建WebViewClient并将webclient设置为webview。 I had to use webview.loadDataWithBaseURL as my urls (in my content) did not have the baseurl but only relative urls. 我不得不使用webview.loadDataWithBaseURL作为我的网址(在我的内容中)没有baseurl但只有相对网址。 You will get the url correctly only when there is a baseurl set using loadDataWithBaseURL. 只有在使用loadDataWithBaseURL设置了baseurl时,才能正确获取url。

public WebViewClient getWebViewClientWithCustomHeader(){
    return new WebViewClient() {
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            try {
                OkHttpClient httpClient = new OkHttpClient();
                com.squareup.okhttp.Request request = new com.squareup.okhttp.Request.Builder()
                        .url(url.trim())
                        .addHeader("<your-custom-header-name>", "<your-custom-header-value>")
                        .build();
                com.squareup.okhttp.Response response = httpClient.newCall(request).execute();

                return new WebResourceResponse(
                        response.header("content-type", response.body().contentType().type()), // You can set something other as default content-type
                        response.header("content-encoding", "utf-8"),  // Again, you can set another encoding as default
                        response.body().byteStream()
                );
            } catch (ClientProtocolException e) {
                //return null to tell WebView we failed to fetch it WebView should try again.
                return null;
            } catch (IOException e) {
                //return null to tell WebView we failed to fetch it WebView should try again.
                return null;
            }
        }
    };

}

I came accross the same problem and solved. 我遇到了同样的问题并解决了。

As said before you need to create your custom WebViewClient and override the shouldInterceptRequest method. 如前所述,您需要创建自定义WebViewClient并覆盖shouldInterceptRequest方法。

WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)

That method should issue a webView.loadUrl while returning an "empty" WebResourceResponse. 该方法应该在返回“空”WebResourceResponse时发出webView.loadUrl。

Something like this: 像这样的东西:

@Override
public boolean shouldInterceptRequest(WebView view, WebResourceRequest request) {

    // Check for "recursive request" (are yor header set?)
    if (request.getRequestHeaders().containsKey("Your Header"))
        return null;

    // Add here your headers (could be good to import original request header here!!!)
    Map<String, String> customHeaders = new HashMap<String, String>();
    customHeaders.put("Your Header","Your Header Value");
    view.loadUrl(url, customHeaders);

    return new WebResourceResponse("", "", null);
}

Here is an implementation using HttpUrlConnection: 这是使用HttpUrlConnection的实现:

class CustomWebviewClient : WebViewClient() {
    private val charsetPattern = Pattern.compile(".*?charset=(.*?)(;.*)?$")

    override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
        try {
            val connection: HttpURLConnection = URL(request.url.toString()).openConnection() as HttpURLConnection
            connection.requestMethod = request.method
            for ((key, value) in request.requestHeaders) {
                connection.addRequestProperty(key, value)
            }

            connection.addRequestProperty("custom header key", "custom header value")

            var contentType: String? = connection.contentType
            var charset: String? = null
            if (contentType != null) {
                // some content types may include charset => strip; e. g. "application/json; charset=utf-8"
                val contentTypeTokenizer = StringTokenizer(contentType, ";")
                val tokenizedContentType = contentTypeTokenizer.nextToken()

                var capturedCharset: String? = connection.contentEncoding
                if (capturedCharset == null) {
                    val charsetMatcher = charsetPattern.matcher(contentType)
                    if (charsetMatcher.find() && charsetMatcher.groupCount() > 0) {
                        capturedCharset = charsetMatcher.group(1)
                    }
                }
                if (capturedCharset != null && !capturedCharset.isEmpty()) {
                    charset = capturedCharset
                }

                contentType = tokenizedContentType
            }

            val status = connection.responseCode
            var inputStream = if (status == HttpURLConnection.HTTP_OK) {
                connection.inputStream
            } else {
                // error stream can sometimes be null even if status is different from HTTP_OK
                // (e. g. in case of 404)
                connection.errorStream ?: connection.inputStream
            }
            val headers = connection.headerFields
            val contentEncodings = headers.get("Content-Encoding")
            if (contentEncodings != null) {
                for (header in contentEncodings) {
                    if (header.equals("gzip", true)) {
                        inputStream = GZIPInputStream(inputStream)
                        break
                    }
                }
            }
            return WebResourceResponse(contentType, charset, status, connection.responseMessage, convertConnectionResponseToSingleValueMap(connection.headerFields), inputStream)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return super.shouldInterceptRequest(view, request)
    }

    private fun convertConnectionResponseToSingleValueMap(headerFields: Map<String, List<String>>): Map<String, String> {
        val headers = HashMap<String, String>()
        for ((key, value) in headerFields) {
            when {
                value.size == 1 -> headers[key] = value[0]
                value.isEmpty() -> headers[key] = ""
                else -> {
                    val builder = StringBuilder(value[0])
                    val separator = "; "
                    for (i in 1 until value.size) {
                        builder.append(separator)
                        builder.append(value[i])
                    }
                    headers[key] = builder.toString()
                }
            }
        }
        return headers
    }
}

Note that this does not work for POST requests because WebResourceRequest doesn't provide POST data. 请注意,这不适用于POST请求,因为WebResourceRequest不提供POST数据。 There is a Request Data - WebViewClient library which uses a JavaScript injection workaround for intercepting POST data. 有一个Request Data - WebViewClient库 ,它使用JavaScript注入解决方法来拦截POST数据。

You can use this: 你可以用这个:

@Override

 public boolean shouldOverrideUrlLoading(WebView view, String url) {

                // Here put your code
                Map<String, String> map = new HashMap<String, String>();
                map.put("Content-Type","application/json");
                view.loadUrl(url, map);
                return false;

            }

用这个:

webView.getSettings().setUserAgentString("User-Agent");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM