android WebView拦截URL请求添加Header及遇到的问题

本文介绍WebView加载URL时添加Header的方法,初始加载添加较简单,若每个页面都要做Header验证,需重写WebViewClient的shouldInterceptRequest方法,使用okhttp3框架插入Header。还提到去掉contentType里的charset=utf - 8可避免页面显示源代码,但遇到百度输入框图标乱码问题未解决。

WebView加载url,如果只需在初始加载的时候添加Header,那么比较简单,只需要这么写即可:

Map<String, String> header = new HashMap<>();
header.put("headkey", "value");
mWebView.loadUrl(url, header);

有些情况下,要求每个页面都要做Header验证,那么就要重写WebViewClient的shouldInterceptRequest方法了:

    private WebViewClient mWebViewClient = new WebViewClient() {

        // Handle API until level 21
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            //API 21以下,此处不考虑兼容性
            return super.shouldInterceptRequest(view, 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, request.getRequestHeaders());
        }

        private WebResourceResponse getNewResponse(String url, Map<String, String> headers) {

            try {
                OkHttpClient httpClient = new OkHttpClient();

                Request.Builder builder = new Request.Builder()
                        .url(url.trim())
                        .addHeader("abc", "zhe-shi-wo-tian-jia-de");

                Set<String> keySet = headers.keySet();
                for (String key : keySet) {
                    builder.addHeader(key, headers.get(key));
                }

                Request request = builder.build();

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

                String conentType = response.header("Content-Type", response.body().contentType().type());
                String temp = conentType.toLowerCase();
                if (temp.contains("charset=utf-8")) {
                    conentType = conentType.replaceAll("(?i)" + "charset=utf-8", "");//不区分大小写的替换
                }
                if (conentType.contains(";")) {
                    conentType = conentType.replaceAll(";", "");
                    conentType = conentType.trim();
                }

                return new WebResourceResponse(
                        conentType,
                        response.header("Content-Encoding", "utf-8"),
                        response.body().byteStream()
                );

            } catch (Exception e) {
                return null;
            }

        }
    };

简单说明下,这个方法有两个重载方法,一个是android api21以下版本的,就不去考虑兼容了,这里只做保留。重新请求用的是okhttp3框架,导入:implementation 'com.squareup.okhttp3:okhttp:3.3.0',可以看到,每次请求我们都插入了自己的Header:addHeader("abc", "zhe-shi-wo-tian-jia-de")。可能有人会注意到,设置contentType的时候把charset=utf-8去掉了,这是因为如果不去掉,加载完毕以后webview页面显示的非常可能是源代码!你没有看错,是源代码而不是界面。截个图就很直观了:

加载百度首页成了这样,当前的contentType包含这样的内容:text/html;charset=utf-8

去掉charset=utf-8,界面就变正常了:

通过抓包我们发现,我们添加的Header已经加上去了,即使打开二级页面也会添加:

细心的人可能会发现,怎么输入框右边的图标变成乱码了:

对比正常的界面:

这正是我遇到的还没解决的问题,通过PC端网页调试,虽然界面不大一样,这个图标大概应该是CSS文件当中一个background的png链接:

但为何通过okhttp3获取的输入流就没有加载成功,有知道问题根源或解决方案的麻烦告诉我下。目前对WebView并没有深入研究。测试了几个网站,也只有百度有这个问题。

 

 

 

<think> 首先,用户的问题是基于之前的引用和上下文。用户提供的引用是关于在Android和JavaFx的WebView添加请求头的方法。用户说:“我想查找在WebView添加请求头的方法 请问WebView添加请求头的实现方法”。所以,我需要根据这些引用提供相关信息。 关键引用: - 引用[1]: 提到在Android WebView中初始化时添加header请求头和token,但ajax请求header带不过去。 - 引用[2]: 提到使用webView.loadUrl(url, header)添加请求头只在一级页面生效,二级页面失效;提到同步cookie。 - 引用[3]: 关于Android拦截WebView加载url和获取POST请求参数。 - 引用[4]: 关于JavaFx WebView通过prepareConnection方法添加自定义请求头。 用户的需求是“WebView添加请求头的实现方法”,但引用中提到了多个平台:Android和JavaFx。用户可能在Android上下文中,因为引用[1]-[3]都是Android相关的,引用[4]是JavaFx。我应该优先考虑Android的实现,因为引用更相关。 系统级指令: - 所有行内数学表达式用$...$(但这里不需要数学,所以可能不适用)。 - 独立公式用$$...$$(同样不适用)。 - LaTeX语法正确(确保代码块正确)。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,如[^1]。 回答结构: - 清晰、逐步解决问题。 - 参考用户上一次问题和我的回答(但这是第一次交互,所以基于当前)。 - 用户说:“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。” 用户提到“用户上一次的问题”,但在这个对话中,这是第一次用户消息。可能用户在引用之前的上下文,但在这个模拟中,我应该忽略“用户上一次的问题”,因为没有先前消息。专注于当前问题。 用户真正的需求:在WebView添加请求头。根据引用,问题在于添加请求头在页面跳转或ajax请求时不生效。 关键点: - 在Android WebView中,使用loadUrl(url, headers)添加请求头只对初始页面有效,对其他页面或ajax请求无效。 - 引用[2]提到同步cookie可能是一个方法。 - 引用[3]提到拦截WebView请求来修改参数。 - 引用[4]展示JavaFx中通过覆盖prepareConnection方法添加请求头。 对于Android WebView: - 解决方案:为了确保所有请求都带有header,需要拦截所有请求添加header。可以使用WebViewClient并覆盖shouldOverrideUrlLoading或shouldInterceptRequest方法。 - 在Android API 21+中,shouldInterceptRequest方法可以用来拦截并修改请求。 实现步骤(针对Android): 1. 创建一个自定义的WebViewClient。 2. 覆盖shouldInterceptRequest方法。 3. 在这个方法中,创建一个新的WebResourceResponse或修改请求。 4. 添加自定义header,如Authorization token。 代码示例:参考引用,我可以提供一个简单的代码片段。 类似引用[4]的JavaFx方法:在Android中,没有prepareConnection,但有shouldInterceptRequest。 用户提到“WebView”,可能泛指,但引用主要是Android。我应该专注于Android,因为引用更相关。 回答结构: - 先解释问题。 - 给出解决方法。 - 提供代码示例。 - 自然地添加引用标识。 - 最后生成相关问题。 自然地添加引用:在引用相关内容时,末尾添加[^n]。 例如,当提到引用[1]的问题时,添加[^1]。 完整回答: 1. 引言:解释在WebView添加请求头的问题。 2. 解决方案:描述如何通过拦截请求来实现。 3. 代码示例:提供Android代码。 4. 注意事项:比如对ajax请求的处理。 5. 相关问题:生成相关问题。 生成相关问题: - 用户指令:生成相关问题。 - 示例中,有§§相关问题§§部分。 - 生成2-3个相关问题基于上下文。 相关问题想法: 1. 如何处理WebView中的ajax请求添加header? 2. WebView添加header时的兼容性问题? 3. 其他平台如JavaFx如何实现? 4. 同步cookie的方法? 参考用户上次问题:但这里没有,所以基于当前。 最终回答大纲: - 回答问题。 - 代码块。 - 相关问题。 确保中文。 </think> ### WebView添加请求头的实现方法 在Android WebView添加请求头时,常见问题是:使用`loadUrl(url, headers)`方法仅在初始页面加载时生效,而对于页面跳转(如a标签)或ajax请求(异步JavaScript请求),请求头无法传递,导致token或自定义header丢失[^1][^2]。根本原因是这些方法只针对首次加载生效,后续请求未携带自定义header。为了解决这个问题,需要拦截所有WebView请求并动态添加header。以下是基于Android平台的逐步实现方法(API 21+),使用WebViewClient的`shouldInterceptRequest`方法拦截并修改请求。注意:该方法适用于HTTP/HTTPS请求,但需处理兼容性和安全机制(如CORS)。 #### 步骤详解 1. **创建自定义WebViewClient**:覆盖`shouldInterceptRequest`方法拦截请求。 2. **添加请求头**:在拦截时,构造新的请求对象并注入自定义header(如token)。 3. **处理ajax请求**:此方法能捕获所有类型的请求(包括ajax),确保header一致传递。 4. **初始化WebView**:在Activity或Fragment中设置自定义WebViewClient。 #### 代码实现示例 以下是一个完整的Android Kotlin代码示例(Java类似)。此示例添加一个Authorization header(token),并处理所有页面和ajax请求: ```kotlin import android.os.Bundle import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse import android.webkit.WebView import android.webkit.WebViewClient import androidx.appcompat.app.AppCompatActivity import java.net.URL import java.util.HashMap class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val webView = WebView(this) setContentView(webView) // 设置自定义WebViewClient以拦截请求 webView.webViewClient = object : WebViewClient() { // 覆盖shouldInterceptRequest方法(API 21+) override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest ): WebResourceResponse? { try { val url = request.url.toString() // 检查是否为需要添加header请求(例如,排除静态资源) if (url.startsWith("http") && !url.contains(".css") && !url.contains(".js")) { val modifiedHeaders = HashMap<String, String>(request.requestHeaders) // 添加自定义header,例如Authorization token modifiedHeaders["Authorization"] = "Bearer YOUR_TOKEN_HERE" modifiedHeaders["Custom-Header"] = "value" // 构造新的请求对象(伪代码:实际需使用OkHttp或HttpURLConnection处理) // 注意:实际实现中,这里需发送新请求并获取响应(简化示例) // 以下为示意逻辑,真实项目需使用网络库处理 val urlObj = URL(url) val connection = urlObj.openConnection().apply { modifiedHeaders.forEach { (key, value) -> setRequestProperty(key, value) } } // 获取响应流(实际中需处理输入流) val responseStream = connection.getInputStream() val mimeType = connection.contentType val encoding = connection.contentEncoding ?: "UTF-8" // 返回WebResourceResponse return WebResourceResponse(mimeType, encoding, responseStream) } } catch (e: Exception) { e.printStackTrace() } // 默认行为:不修改请求 return super.shouldInterceptRequest(view, request) } } // 加载初始URL(可选添加初始headerwebView.loadUrl("https://example.com") } } ``` #### 关键注意事项 - **兼容性**:`shouldInterceptRequest`需要Android 5.0 (API 21)及以上。对于旧版本(API < 21),可使用`shouldOverrideUrlLoading`拦截导航请求,但无法处理ajax[^2][^3]。 - **性能影响**:频繁拦截请求可能降低WebView性能,建议仅对特定URL添加header。 - **安全机制**:添加header时需处理HTTPS和CORS(跨域资源共享),避免被浏览器阻止[^1]。 - **其他平台**:如JavaFx WebView,可通过覆盖`prepareConnection`方法添加请求头(类似引用[4]的实现)[^4]。 - **备选方案**:如果拦截复杂,可考虑同步cookie作为替代(使用`CookieManager`),但header更灵活[^2]。 此方法在Android WebView中能有效解决ajax和页面跳转时header丢失的问题。如果遇到具体错误,提供更多细节可进一步优化。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值