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

Android WebView使用OkHttp携带Authorization头出现编码乱码问题求解

问题复现

参考Stack Overflow回答《Send authorization header with every request in webview using okhttp in android》开发,运行后WebView页面出现乱码,尝试手动设置content-type为text/html、text/plain均未解决。

核心实现逻辑

自定义WebViewClient,重写shouldInterceptRequest方法,使用OkHttp发起请求时携带Bearer类型的Authorization头,再将请求响应封装为WebResourceResponse返回给WebView加载。

相关代码

自定义WebViewClient代码

val wvc: WebViewClient = object : WebViewClient() {
    override fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? {
        return try {
            // val acToken: String = pref.getString("token", "DEFAULT")
            val okHttpClient = OkHttpClient()
            val request: Request = Request.Builder().url(url).addHeader("Authorization", "Bearer $bearer").build()
            val response: Response = okHttpClient.newCall(request).execute()
            WebResourceResponse(
                response.header("content-type", response.body()?.contentType()?.type()),  // 可自定义默认content-type
                response.header("content-encoding", "UTF-8"),  // 可自定义默认编码
                response.body()?.byteStream()
            )
        } catch (e: IOException) {
            e.printStackTrace()
            null
        }
    }
}

WebView绑定配置代码

webview_comp.setWebViewClient(wvc);
      
url?.let { webview_comp.loadUrl(it) };

乱码效果

WebView乱码截图

解决方案

乱码问题由两处参数传递错误和压缩处理逻辑冲突导致,按以下步骤修改即可解决:

  • 参数位置错误修正:WebResourceResponse构造方法的第二个参数是content-encoding,对应传输压缩格式(如gzip、deflate),原代码错误地将字符编码UTF-8传到了该位置。字符编码需要放在content-type的charset参数中。
  • content-type取值修正:原有代码只取了contentType的type(如text),丢失了子类型(如html)和编码信息,需要取完整的content-type字符串。
  • 压缩逻辑冲突修正:OkHttp默认会自动解压gzip格式的响应,此时如果直接把响应头中的content-encoding: gzip传给WebView,WebView会尝试对已经解压过的流二次解压,导致乱码,需要手动移除该响应头。
  • 兜底编码补充:如果服务端没有返回charset信息,手动给content-type追加charset=utf-8作为兜底。

修正后代码

val wvc: WebViewClient = object : WebViewClient() {
    override fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? {
        return try {
            val okHttpClient = OkHttpClient()
            val request: Request = Request.Builder()
                .url(url)
                .addHeader("Authorization", "Bearer $bearer")
                .build()
            val response: Response = okHttpClient.newCall(request).execute()
            
            // 处理content-type,补全缺失的charset
            val contentType = response.header("content-type") ?: run {
                response.body()?.contentType()?.toString() ?: "text/html; charset=utf-8"
            }.let {
                if (!it.contains("charset=", ignoreCase = true)) {
                    "$it; charset=utf-8"
                } else it
            }
            
            WebResourceResponse(
                contentType,
                null, // 无需传入content-encoding,OkHttp已自动完成gzip解压
                response.body()?.byteStream()
            )
        } catch (e: IOException) {
            e.printStackTrace()
            null
        }
    }
}

内容的提问来源于stack exchange,提问作者IRON MAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 01:06:05