You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
}

问题根源分析

  1. 全局拦截请求导致静态资源失效:shouldInterceptRequest拦截了所有请求(包括JS、CSS、图片等静态资源),所有请求都返回了POST接口的HTML响应,导致页面依赖的静态资源无法加载,只能显示纯HTML结构。
  2. Content-Type头部冲突:请求体是JSON格式,但设置了application/x-www-form-urlencoded的Content-Type,服务器无法正确解析请求体,可能返回异常页面或无样式的HTML。
  3. MIME类型识别错误:初始页面URL可能没有后缀,getMimeType返回null或错误类型,WebView无法识别为HTML进行渲染。
  4. 同步请求阻塞主线程: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:44:59