loadURL
有参数extraHeaders
,但这些仅适用于初始请求。 所有后续请求都不包含头信息。 我查看了WebViewClient
中的所有重写方法,但没有任何方法可以向资源请求添加头信息 - onLoadResource(WebView view, String url)
。 希望能得到帮助。谢谢, 雷伊
loadURL
有参数extraHeaders
,但这些仅适用于初始请求。 所有后续请求都不包含头信息。 我查看了WebViewClient
中的所有重写方法,但没有任何方法可以向资源请求添加头信息 - onLoadResource(WebView view, String url)
。 希望能得到帮助。尝试
loadUrl(String url, Map<String, String> extraHeaders)
要在资源加载请求中添加标头,请创建自定义的 WebViewClient 并覆盖以下内容:
API 24+:
WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
or
WebResourceResponse shouldInterceptRequest(WebView view, String url)
view.loadUrl("http://www.facebook.com", extraHeaders)
加载网页时,WebView会发送多个类似于'http://static.fb.com/images/logo.png'
等的资源请求。对于这些请求,额外的头信息将不会被添加。并且在此类资源请求期间,不会调用shouldOverrideUrlLoading回调函数。回调函数'OnLoadResource'会被调用,但是没有办法在此时设置头信息。 - MediumOneWebViewClient.shouldInterceptRequest(android.webkit.WebView view, java.lang.String url)
。查看API获取更多信息。 - yorkwshouldInterceptRequest
方法实现这一点,请问能否解释一下如何实现? - MediumOne你需要使用WebViewClient.shouldInterceptRequest来拦截每个请求。
在每次拦截时,你需要获取URL并自己发起请求,然后返回内容流:
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);
如果您的最低API版本是21级,您可以使用新的shouldInterceptRequest方法,它提供了额外的请求信息(例如标头),而不仅仅是URL。
public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request)
代替,更多信息请查看这里。 - Hirdesh Vishwdewasuper.shouldInterceptRequest()
并不能像 @ErikReppen 描述的那样使修改后的请求生效。如果可以这样做,那就太好了,但 API 并不是这样工作的。超级调用只会返回 null 而不会发出请求。返回 null 告诉 Web 客户端不要拦截请求,并且请求将在没有修改标头的情况下进行。 - Jeff Lockhart也许我的回复有点晚,但它涵盖了21级以下和以上的API。
要添加标题,我们应该拦截每个请求并创建带有所需标题的新请求。
因此,我们需要覆盖两种情况下调用的shouldInterceptRequest方法: 1. 直到21级的API; 2. 21级以上的API。
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;
}
}
});
如果需要处理响应类型,您可以进行更改。 return new WebResourceResponse(
null, // <- Change here
response.header("content-encoding", "utf-8"),
response.body().byteStream()
);
至
return new WebResourceResponse(
getMimeType(url), // <- Change here
response.header("content-encoding", "utf-8"),
response.body().byteStream()
);
并添加方法
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;
}
如前所述,您可以这样做:
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);
我测试了一下,在一个MVC控制器中,我扩展了Authorize属性来检查头部信息,头部信息确实存在。
我测试了一下,在我扩展了Authorize属性的MVC控制器上进行了测试,该属性用于检查请求头,请求头是存在的。
这对我有效:
首先,您需要创建一个方法,该方法将返回您想要添加到请求中的标头:
private Map<String, String> getCustomHeaders()
{
Map<String, String> headers = new HashMap<>();
headers.put("YOURHEADER", "VALUE");
return headers;
}
接下来您需要创建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;
}
};
}
将WebViewClient添加到您的WebView中:
webView.setWebViewClient(getWebViewClient());
希望这可以帮助。
loadUrl(String url, Map<String, String> additionalHttpHeaders)
表示添加额外的头部信息。 - AbhinayMe以下是使用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
}
}
通过跳过 loadUrl 方法并编写自己的 loadPage,使用 Java 的 HttpURLConnection 可以控制所有标头。然后使用 webview 的 loadData 方法显示响应。
Google 提供的标头没有访问权限。它们在 WebView 源代码中的 JNI 调用中。
这个对我有用。创建下面的WebViewClient并将其设置为您的webview。由于我的内容中的urls只有相对urls,所以我不得不使用webview.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;
}
}
};
}
class CustomHeaderWebViewClient(headerValue: String) : WebViewClient() { }
private val authHeaderInjection = """
(function() {
const originalFetch = window.fetch;
window.fetch = function(input, init) {
init = init || {};
init.headers = init.headers || {};
init.headers['My-Header'] = '$headerValue';
return originalFetch.apply(this, arguments);
};
})();
""".trimIndent()
你需要重写onPageStarted方法,在每次导航时执行JavaScript注入:
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
view?.evaluateJavascript(authHeaderInjection) { Timber.d(it) }
super.onPageStarted(view, url, favicon)
}
注意:根据WebView内容的实现方式,您可以选择不同的回调函数。
注意:请注意,根据您的需求,当使用webview.loadUrl(url, yourHeaders)
时,您可能仍然需要手动添加其他自定义标头。
import android.graphics.Bitmap
import android.webkit.WebView
import android.webkit.WebViewClient
import timber.log.Timber
class CustomHeaderWebViewClient(headerValue: String) : WebViewClient() {
private val authHeaderInjection = """
(function() {
const originalFetch = window.fetch;
window.fetch = function(input, init) {
init = init || {};
init.headers = init.headers || {};
init.headers['My-Header'] = '${headerValue}';
return originalFetch.apply(this, arguments);
};
})();
""".trimIndent()
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
view?.evaluateJavascript(authHeaderInjection) { Timber.d(it) }
super.onPageStarted(view, url, favicon)
}
}
shouldInterceptRequest
无法拦截 request.body
。
我建议在 webview.loadUrl
前重置 userAgent。
例如:
webview.settings.userAgentString += " key1/value1 key2/value2"