Android WebView API21+中如何通过shouldInterceptRequest获取POST请求数据?
解决Android WebView API21+中shouldInterceptRequest无法获取POST参数的问题
没错,这确实是Android WebView API 21+以来一个挺棘手的问题——WebResourceRequest虽然给拦截请求带来了更多便利,但它确实没有提供直接获取POST请求体的接口。不过不用担心,我整理了几个经过验证的可行方案,你可以根据自己的场景选择:
方案一:用OkHttp替换WebView默认网络栈(无需前端配合)
这个方案的核心是让WebView通过OkHttp发起所有网络请求,借助OkHttp的Interceptor来捕获完整的请求(包括POST体),然后在shouldInterceptRequest里处理自定义逻辑。
步骤示例:
- 配置带Interceptor的OkHttpClient,用于捕获POST参数:
// 缓存POST参数的容器,注意线程安全 private final ConcurrentHashMap<String, String> postParamCache = new ConcurrentHashMap<>(); OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(chain -> { Request request = chain.request(); // 仅处理POST请求 if ("POST".equals(request.method()) && request.body() != null) { Buffer buffer = new Buffer(); request.body().writeTo(buffer); String postParams = buffer.readUtf8(); // 缓存参数,用请求URL作为键 postParamCache.put(request.url().toString(), postParams); } return chain.proceed(request); }) // 同步WebView的Cookie(可选,根据需求添加) .cookieJar(new CookieJar() { @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { // 将OkHttp的Cookie同步到WebView CookieManager.getInstance().setCookie(url.host(), CookieManager.getInstance().getCookie(url.host())); } @Override public List<Cookie> loadForRequest(HttpUrl url) { // 从WebView获取Cookie给OkHttp String cookieStr = CookieManager.getInstance().getCookie(url.host()); if (cookieStr == null) return Collections.emptyList(); return Cookie.parseAll(url, cookieStr); } }) .build();
- 自定义WebViewClient,在
shouldInterceptRequest中使用OkHttp处理请求:
webView.setWebViewClient(new WebViewClient() { // API26+推荐使用异步重载,避免阻塞主线程 @Override public void shouldInterceptRequest(WebView view, WebResourceRequest request, Callback callback) { new Thread(() -> { try { String url = request.getUrl().toString(); // 构建OkHttp请求 okhttp3.Request.Builder okRequestBuilder = new okhttp3.Request.Builder() .url(url) .headers(Headers.of(request.getRequestHeaders())); // 从缓存中取出POST参数,构建请求体 if ("POST".equals(request.getMethod())) { String postParams = postParamCache.get(url); if (postParams != null) { String contentType = request.getRequestHeaders().getOrDefault("Content-Type", "application/x-www-form-urlencoded"); okRequestBuilder.post(RequestBody.create(MediaType.parse(contentType), postParams)); } } // 执行请求并返回响应 okhttp3.Response okResponse = okHttpClient.newCall(okRequestBuilder.build()).execute(); WebResourceResponse webResponse = new WebResourceResponse( okResponse.header("Content-Type"), okResponse.header("Content-Encoding"), okResponse.body().byteStream() ); callback.onResponse(webResponse); // 清理缓存的参数 postParamCache.remove(url); } catch (IOException e) { e.printStackTrace(); callback.onResponse(null); } }).start(); } // 兼容API21-25的同步方法 @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { try { String url = request.getUrl().toString(); okhttp3.Request.Builder okRequestBuilder = new okhttp3.Request.Builder() .url(url) .headers(Headers.of(request.getRequestHeaders())); if ("POST".equals(request.getMethod())) { String postParams = postParamCache.get(url); if (postParams != null) { String contentType = request.getRequestHeaders().getOrDefault("Content-Type", "application/x-www-form-urlencoded"); okRequestBuilder.post(RequestBody.create(MediaType.parse(contentType), postParams)); } } okhttp3.Response okResponse = okHttpClient.newCall(okRequestBuilder.build()).execute(); WebResourceResponse webResponse = new WebResourceResponse( okResponse.header("Content-Type"), okResponse.header("Content-Encoding"), okResponse.body().byteStream() ); postParamCache.remove(url); return webResponse; } catch (IOException e) { e.printStackTrace(); return super.shouldInterceptRequest(view, request); } } });
优缺点:
- ✅ 无需前端配合,能拦截所有WebView发起的POST请求
- ✅ 兼容性较好,覆盖API21+
- ⚠️ 需要处理Cookie同步、缓存等细节,实现相对复杂
- ⚠️ API21-25的同步方法会阻塞主线程,需注意性能
方案二:前端+JSInterface配合(适合自有网页)
如果你的WebView加载的是自己开发的网页,可以通过注入JavaScript代码监听POST请求,再通过JavascriptInterface将参数传递给原生。
步骤示例:
- 添加JavascriptInterface用于接收参数:
private final ConcurrentHashMap<String, String> postParamCache = new ConcurrentHashMap<>(); // 初始化WebView时添加接口 webView.addJavascriptInterface(new Object() { @JavascriptInterface public void onPostRequest(String url, String params) { // 缓存POST参数 postParamCache.put(url, params); } }, "AndroidPostBridge");
- 页面加载完成后注入监听JS:
webView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // 注入JS监听XMLHttpRequest和fetch的POST请求 String injectJs = "(() => {" + "// 监听XMLHttpRequest" + "const originalXhrOpen = XMLHttpRequest.prototype.open;" + "XMLHttpRequest.prototype.open = function(method, url) {" + "this._requestUrl = url;" + "this._requestMethod = method;" + "originalXhrOpen.apply(this, arguments);" + "};" + "const originalXhrSend = XMLHttpRequest.prototype.send;" + "XMLHttpRequest.prototype.send = function(body) {" + "if (this._requestMethod === 'POST' && this._requestUrl) {" + "AndroidPostBridge.onPostRequest(this._requestUrl, body || '');" + "}" + "originalXhrSend.apply(this, arguments);" + "};" + "// 监听fetch请求" + "const originalFetch = fetch;" + "window.fetch = function(resource, options) {" + "let reqUrl = typeof resource === 'string' ? resource : resource.url;" + "let reqMethod = options?.method || 'GET';" + "if (reqMethod === 'POST') {" + "let reqBody = options?.body || '';" + "// 处理FormData类型的参数(可选)" + "if (reqBody instanceof FormData) {" + "let formDataStr = [];" + "for (let pair of reqBody.entries()) {" + "formDataStr.push(pair[0] + '=' + encodeURIComponent(pair[1]));" + "}" + "AndroidPostBridge.onPostRequest(reqUrl, formDataStr.join('&'));" + "} else {" + "AndroidPostBridge.onPostRequest(reqUrl, reqBody);" + "}" + "}" + "return originalFetch.apply(this, arguments);" + "};" + "})();"; view.evaluateJavascript(injectJs, null); } @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { if ("POST".equals(request.getMethod())) { String url = request.getUrl().toString(); String postParams = postParamCache.get(url); if (postParams != null) { // 在这里使用POST参数处理你的拦截逻辑 Log.d("POST_PARAMS", "URL: " + url + " Params: " + postParams); // 处理完成后清理缓存 postParamCache.remove(url); } } return super.shouldInterceptRequest(view, request); } });
优缺点:
- ✅ 实现简单,无需处理复杂的网络栈替换
- ✅ 不会阻塞主线程
- ⚠️ 依赖前端配合,无法处理第三方网页
- ⚠️ 若页面有CSP(内容安全策略)限制,可能导致JS注入失败
方案三:反射Hook WebView内部请求(不推荐)
通过反射获取WebView内部的请求对象来读取POST体,但这种方式严重依赖WebView的内部实现,不同Android版本、不同厂商的WebView可能有差异,极易导致崩溃,仅在特定场景下临时使用。
注意:
- 不建议在生产环境使用,维护成本极高
- 需要针对不同Android版本编写不同的反射逻辑
内容的提问来源于stack exchange,提问作者casolorz




