Android WebView 拦截请求导致的会话不一致问题及解决方案
layout: post title: “Android WebView 拦截请求导致的会话不一致问题及解决方案” date: 2025-12-23 21:00:00 +0000 categories: android webview tags: android webview okhttp cookie —
问题现象
在 Android 开发中,常通过重写 WebView 的 shouldInterceptRequest 方法,使用自定义网络栈(如 OkHttp)来接管部分资源请求(例如仅拦截 GET 请求以使用 HTTPDNS 或统一缓存)。
这种部分拦截的策略极易引发一个严重问题:会话(Session)不一致。 用户在登录后(原生网络栈 POST 请求),后续页面依然处于未登录状态;或图形验证码校验始终不过。
根本原因
会话不一致的根本原因是:原生 WebView 的 CookieManager 与第三方网络库(OkHttp)的 Cookie 存储相互隔离且未同步。
用户登录流程的时序割裂:
1. [GET] 加载登录页面 → 被拦截,走 OkHttp 请求
2. [POST] 提交登录表单 → 未被拦截,走 WebView 原生请求,服务端返回 Set-Cookie
3. [GET] 获取用户信息 → 被拦截,走 OkHttp 请求
- WebView 原生请求收到的
Set-Cookie会保存在CookieManager中。 - 后续拦截走 OkHttp 的请求,如果没有提取并携带
CookieManager中的 Cookie,或者 OkHttp 响应的Set-Cookie没有反向同步给CookieManager,两套网络栈使用的就是不同的 Session 标识。
解决方案
核心思路:在拦截逻辑中,充当 Cookie 的双向同步桥梁。
注:
WebResourceRequest.requestHeaders在调用shouldInterceptRequest时,系统已经自动从CookieManager注水了最新的 Cookie,因此只需要关注响应后的 Cookie 回写。
在拦截实现中增加响应后的 Cookie 同步逻辑:
private fun getResponseByOkHttp(request: WebResourceRequest?): WebResourceResponse? {
request ?: return null
val url = request.url.toString()
val requestBuilder = okhttp3.Request.Builder()
.url(url)
.method(request.method, null)
// 1. 携带 WebView 已有的 Cookie (系统已注入到 requestHeaders)
request.requestHeaders?.forEach { (key, value) ->
requestBuilder.addHeader(key, value)
}
val response = okhttpClient.newCall(requestBuilder.build()).execute()
// 2. 关键:同步响应头中的 Set-Cookie 到 WebView的 CookieManager
// 必须在判断状态码之前同步,以防 302 重定向丢失 Cookie
syncCookiesToManager(url, response)
if (response.code != 200) {
response.close()
return null
}
val body = response.body ?: return null
// 构建并返回 WebResourceResponse...
}
/**
* 将 OkHttp 响应中的 Set-Cookie 写入 CookieManager
*/
private fun syncCookiesToManager(url: String, response: okhttp3.Response) {
val cookies = response.headers("Set-Cookie")
if (cookies.isNotEmpty()) {
val cookieManager = android.webkit.CookieManager.getInstance()
cookies.forEach {
cookieManager.setCookie(url, it)
}
cookieManager.flush() // 确保立即持久化到本地,防止进程被杀导致丢失
}
}
扩展建议
1. 过滤第三方域名 并非所有请求都适合拦截。涉及第三方支付、授权的网页,建议通过白名单/黑名单机制过滤,让原生 WebView 自行处理,避免引发未知的安全或跨域 Cookie 异常。
2. HTTPDNS 附带效应
使用 HTTPDNS 替换域名为 IP 后发起请求,其真实的 Host 头需要手动补全,否则可能触发 CDN 阻断或服务端 Host 校验严格环境下的 400 错误。
小结
WebView 请求拦截是优化利器,但拦截了请求,就必须完整接管并维护 HTTP 的状态机(Cookie/Session)。构建稳定的双向 Cookie 同步机制,是此类架构落地的必修课。