You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android WebView API21+中如何通过shouldInterceptRequest获取POST请求数据?

解决Android WebView API21+中shouldInterceptRequest无法获取POST参数的问题

没错,这确实是Android WebView API 21+以来一个挺棘手的问题——WebResourceRequest虽然给拦截请求带来了更多便利,但它确实没有提供直接获取POST请求体的接口。不过不用担心,我整理了几个经过验证的可行方案,你可以根据自己的场景选择:

方案一:用OkHttp替换WebView默认网络栈(无需前端配合)

这个方案的核心是让WebView通过OkHttp发起所有网络请求,借助OkHttp的Interceptor来捕获完整的请求(包括POST体),然后在shouldInterceptRequest里处理自定义逻辑。

步骤示例:

  1. 配置带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();
  1. 自定义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将参数传递给原生。

步骤示例:

  1. 添加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");
  1. 页面加载完成后注入监听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

火山引擎 最新活动