Android WebView导航时出现419 | Page Expired问题排查求助
问题说明
使用Android WebView进行导航操作时,页面返回419 | Page Expired错误,相关代码如下:
@SuppressLint("SetJavaScriptEnabled") fun loadWebview(url:String){ var webView:WebView = findViewById(R.id.webView) //begin new val webSettings = webView.settings webSettings.javaScriptEnabled = true webSettings.allowFileAccess = true webSettings.allowContentAccess = true webSettings.databaseEnabled = true webSettings.javaScriptCanOpenWindowsAutomatically = true //improve webView performance webView.settings.setRenderPriority(WebSettings.RenderPriority.HIGH) webView.settings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); webView.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY webSettings.domStorageEnabled = true webSettings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS webSettings.useWideViewPort = true webSettings.savePassword = true webSettings.saveFormData = true webSettings.setEnableSmoothTransition(true) webSettings.setDomStorageEnabled(true); webView.getSettings().setDomStorageEnabled(true); if (Build.VERSION.SDK_INT >= 21) { webSettings.mixedContentMode = 0 webView.setLayerType(View.LAYER_TYPE_HARDWARE, null) } else if (Build.VERSION.SDK_INT >= 19) { webView.setLayerType(View.LAYER_TYPE_HARDWARE, null) } else { webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null) } webView.webChromeClient = WebChromeClient() CookieSyncManager.createInstance(this) CookieSyncManager.getInstance().startSync() val cookieManager: CookieManager = CookieManager.getInstance() cookieManager.setAcceptCookie(true) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true) } webView.loadUrl(url) }
代码问题分析
419 Page Expired通常和后端的CSRF令牌验证失败有关,结合你的代码,主要问题如下:
缓存模式重复设置
代码中先后设置了LOAD_CACHE_ELSE_NETWORK和LOAD_DEFAULT两种缓存模式,这会导致WebView的缓存逻辑混乱,可能加载了过期的页面内容或CSRF令牌,引发419错误。过时的Cookie同步方式
CookieSyncManager从API 21开始已被废弃,继续使用可能导致Cookie无法正确同步到WebView,使得请求时无法携带有效的CSRF令牌。冗余的DOM存储设置
代码中重复三次设置domStorageEnabled = true,虽然不直接引发错误,但属于无效冗余代码。废弃的API调用
savePassword从API 19开始已被废弃,保留该设置会产生警告,且无实际作用。未设置WebViewClient
缺少自定义的WebViewClient,页面导航时可能无法正确处理请求上下文,导致CSRF令牌等关键Cookie没有被正确携带到新请求中。
修复方案
针对上述问题,修改代码如下:
@SuppressLint("SetJavaScriptEnabled") fun loadWebview(url: String) { val webView: WebView = findViewById(R.id.webView) val webSettings = webView.settings // 基础配置 webSettings.javaScriptEnabled = true webSettings.allowFileAccess = true webSettings.allowContentAccess = true webSettings.databaseEnabled = true webSettings.javaScriptCanOpenWindowsAutomatically = true webSettings.domStorageEnabled = true // 性能优化配置 webSettings.renderPriority = WebSettings.RenderPriority.HIGH webSettings.cacheMode = WebSettings.LOAD_DEFAULT // 统一缓存模式 webView.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY webSettings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS webSettings.useWideViewPort = true webSettings.saveFormData = true webSettings.setEnableSmoothTransition(true) // 硬件加速配置 if (Build.VERSION.SDK_INT >= 21) { webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW // 使用常量替代魔法值0 webView.setLayerType(View.LAYER_TYPE_HARDWARE, null) } else if (Build.VERSION.SDK_INT >= 19) { webView.setLayerType(View.LAYER_TYPE_HARDWARE, null) } else { webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null) } webView.webChromeClient = WebChromeClient() // Cookie配置(替换过时的CookieSyncManager) val cookieManager = CookieManager.getInstance() cookieManager.setAcceptCookie(true) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cookieManager.setAcceptThirdPartyCookies(webView, true) } // 同步Cookie(API 21+使用flush,旧版本兼容处理) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cookieManager.flush() } else { CookieSyncManager.createInstance(this).startSync() } // 设置WebViewClient,确保导航时正确携带Cookie webView.webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { request?.url?.let { view?.loadUrl(it.toString()) } return true } } webView.loadUrl(url) }
关键修改点说明
- 统一缓存模式为
LOAD_DEFAULT,避免缓存逻辑冲突; - 替换
CookieSyncManager为推荐的CookieManager.flush()(针对API 21+),确保Cookie同步正常; - 移除废弃的
savePassword设置,清理无效代码; - 添加自定义
WebViewClient,确保页面跳转时请求上下文正确传递,保证Cookie携带完整; - 使用常量
WebSettings.MIXED_CONTENT_ALWAYS_ALLOW替代魔法值0,提升代码可读性。
额外注意事项
如果后端使用Laravel等框架,需要确保WebView正确保存XSRF-TOKEN Cookie,并且在POST请求时自动携带X-XSRF-TOKEN请求头。可以通过注入JavaScript自动设置请求头,或者让后端在响应中正确配置Cookie的SameSite属性,确保WebView可以正常获取和使用CSRF令牌。
内容的提问来源于stack exchange,提问作者Enamul Haque

