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) };
乱码效果

解决方案
乱码问题由两处参数传递错误和压缩处理逻辑冲突导致,按以下步骤修改即可解决:
- 参数位置错误修正:
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
相关产品推荐
相关产品推荐

