Android WebView重写shouldInterceptRequest后加载纯HTML问题求助
Android WebView POST请求后页面显示纯HTML问题解决
需要在Android WebView中携带请求头和JSON表单体向指定URL发送POST请求,编写代码后WebView加载页面时仅显示纯HTML内容,无法正常渲染。已尝试开启JavaScript、DOM存储等WebView设置,调整MIME类型,但问题仍未解决。
原代码:
binding.webView.apply { settings.javaScriptEnabled = true settings.domStorageEnabled = true settings.allowContentAccess = true settings.loadWithOverviewMode = true settings.javaScriptCanOpenWindowsAutomatically = true settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading( view: WebView?, request: WebResourceRequest? ): Boolean { showLoadingView() return false } override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) hideLoadingView() } override fun shouldInterceptRequest( view: WebView?, request: WebResourceRequest ): WebResourceResponse { return postDataOkHttpClient(supportCenter) } } loadUrl(supportCenter?.consumerUrl ?: "") } private fun postDataOkHttpClient(supportCenter: SupportCenter?): WebResourceResponse { val client = OkHttpClient() val mediaType = "application/json; charset=utf-8".toMediaType() val jsonObject = JSONObject() jsonObject.put("token", supportCenter?.token ?: "") jsonObject.put("lang", supportCenter?.lang ?: "") jsonObject.put("channel", supportCenter?.channel ?: "") val body = jsonObject.toString().toRequestBody(mediaType) val request = Request.Builder() .url(supportCenter?.consumerUrl ?: "") .addHeader("Authorization", supportCenter?.authToken ?: "") .addHeader("Content-Type", "application/x-www-form-urlencoded") .post(body) .build() val response = client.newCall(request).execute() return WebResourceResponse( getMimeType(supportCenter?.consumerUrl ?: ""), response.header("content-encoding", "utf-8"), response.body!!.byteStream() ) } private fun getMimeType(url: String?): String? { var type: String? = null val extension = MimeTypeMap.getFileExtensionFromUrl(url) if (extension != null) { when (extension) { "js" -> { return "text/javascript" } "woff" -> { return "application/font-woff" } "woff2" -> { return "application/font-woff2" } "ttf" -> { return "application/x-font-ttf" } "eot" -> { return "application/vnd.ms-fontobject" } "svg" -> { return "image/svg+xml" } else -> type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) } } return type }
问题根源分析
- 全局拦截请求导致静态资源失效:
shouldInterceptRequest拦截了所有请求(包括JS、CSS、图片等静态资源),所有请求都返回了POST接口的HTML响应,导致页面依赖的静态资源无法加载,只能显示纯HTML结构。 - Content-Type头部冲突:请求体是JSON格式,但设置了
application/x-www-form-urlencoded的Content-Type,服务器无法正确解析请求体,可能返回异常页面或无样式的HTML。 - MIME类型识别错误:初始页面URL可能没有后缀,
getMimeType返回null或错误类型,WebView无法识别为HTML进行渲染。 - 同步请求阻塞主线程:
execute()同步请求会阻塞WebView所在的主线程,导致页面加载流程异常。
修正后的代码
1. 调整WebViewClient,仅拦截初始页面请求
binding.webView.apply { settings.javaScriptEnabled = true settings.domStorageEnabled = true settings.allowContentAccess = true settings.loadWithOverviewMode = true settings.javaScriptCanOpenWindowsAutomatically = true settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW webViewClient = object : WebViewClient() { // 标记是否为初始页面请求 private var isInitialRequest = true override fun shouldOverrideUrlLoading( view: WebView?, request: WebResourceRequest? ): Boolean { showLoadingView() return false } override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) hideLoadingView() // 初始请求完成后,不再拦截后续请求 isInitialRequest = false } override fun shouldInterceptRequest( view: WebView?, request: WebResourceRequest ): WebResourceResponse? { // 仅处理初始的GET请求(loadUrl默认是GET,替换为POST) if (isInitialRequest && request.method.equals("GET", ignoreCase = true)) { return postDataOkHttpClient(supportCenter) } // 其他请求正常放行 return super.shouldInterceptRequest(view, request) } } loadUrl(supportCenter?.consumerUrl ?: "") }
2. 修正POST请求的Content-Type与异常处理
private fun postDataOkHttpClient(supportCenter: SupportCenter?): WebResourceResponse? { // 空值校验,避免空指针 val targetUrl = supportCenter?.consumerUrl ?: return null val client = OkHttpClient.Builder() .callTimeout(10, TimeUnit.SECONDS) .build() val mediaType = "application/json; charset=utf-8".toMediaType() val jsonObject = JSONObject().apply { put("token", supportCenter.token ?: "") put("lang", supportCenter.lang ?: "") put("channel", supportCenter.channel ?: "") } val body = jsonObject.toString().toRequestBody(mediaType) val request = Request.Builder() .url(targetUrl) .addHeader("Authorization", supportCenter.authToken ?: "") // 保持Content-Type与请求体类型一致 .addHeader("Content-Type", "application/json; charset=utf-8") .post(body) .build() return runCatching { val response = client.newCall(request).execute() // 请求失败时放行,让WebView默认处理错误 if (!response.isSuccessful) { return null } // 明确指定HTML的MIME类型,确保WebView正确渲染 WebResourceResponse( "text/html", response.header("content-encoding", "utf-8"), response.body?.byteStream() ) }.getOrNull() }
3. 保留原getMimeType方法
该方法可继续用于处理静态资源的MIME类型识别,不影响主流程。
额外注意事项
- 确保服务器返回的HTML内容完整,包含正确的静态资源引用路径。
- 若仍存在渲染问题,可检查WebView的
userAgent设置,是否与浏览器一致,部分服务器会根据userAgent返回不同内容。
内容的提问来源于stack exchange,提问作者Shafqat Jamil
相关产品推荐
相关产品推荐

