Android中webview_flutter POST请求自定义Header的实现问题求助
解决Android下webview_flutter POST请求带Header后页面无样式、JS报错的问题
问题根源分析
- 资源加载路径错误:用
loadHtmlString加载纯HTML时,页面内的相对路径资源(CSS、JS、图片)默认以about:blank为基准URL,无法正确请求服务器上的资源,导致页面无样式。 - jQuery注入时机错误:原代码在
loadHtmlString前执行注入,此时页面DOM尚未初始化,注入的脚本无法生效,且页面原有依赖jQuery的代码已提前执行,抛出未定义错误。 - 链接跳转无请求:页面base URL为
about:blank,点击相对链接时请求的URL无效,因此服务器无日志。
可行解决方案
方案一:给loadHtmlString设置baseUrl(最直接有效)
通过指定baseUrl,让页面内的相对路径资源以服务器域名为基准加载,同时调整jQuery注入时机到页面加载完成后。
修改代码如下:
- 初始化
WebViewController时添加页面加载完成监听:
@override void initState() { super.initState(); controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setNavigationDelegate( NavigationDelegate( // 页面加载完成后注入jQuery onPageFinished: (String url) async { await injectJQuery(); }, ), ); _loadRequestWithAuthHeader(); controller.addJavaScriptChannel( 'Flutter', onMessageReceived: (JavaScriptMessage message) { print('JavaScript Error: ${message.message}'); }, ); }
- 修改
_loadRequestWithAuthHeader中的loadHtmlString调用,添加baseUrl参数:
if (response.statusCode == 200) { // 传入服务器域名作为baseUrl,解决相对资源加载问题 await controller.loadHtmlString( response.body, baseUrl: Config.domain, ); }
- 保留原
injectJQuery方法即可,此时注入时机正确,脚本会生效。
方案二:针对Android平台使用原生WebView的POST带Header能力
借助webview_flutter_android插件的扩展能力,直接调用原生WebView的postUrl方法,绕过WebViewController.loadRequest的限制:
- 添加依赖到
pubspec.yaml:
dependencies: webview_flutter: ^4.0.0 webview_flutter_android: ^3.0.0
- 修改请求逻辑,针对Android平台使用原生实现:
import 'package:webview_flutter_android/webview_flutter_android.dart'; import 'dart:convert'; import 'dart:typed_data'; Future<void> _loadRequestWithAuthHeader() async { const storage = FlutterSecureStorage(); final token = await storage.read(key: 'token'); if (token != null) { final url = Uri.parse('${Config.domain}/mobile_index.php'); final headers = { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', }; // 针对Android平台使用原生postUrl方法 if (controller.platform is AndroidWebViewController) { await (controller.platform as AndroidWebViewController).postUrl( url: url.toString(), postData: Uint8List.fromList(utf8.encode('')), // POST请求体,按需修改 headers: headers, ); } else { // iOS平台可直接用loadRequest await controller.loadRequest( url, method: LoadRequestMethod.post, headers: headers, ); } } }
方案三:改用Cookie传递认证信息(需服务器配合)
手动发起POST请求后,将服务器返回的Set-Cookie保存,再让WebView加载页面时自动携带Cookie:
final response = await http.post(url, headers: headers); if (response.statusCode == 200) { // 提取Set-Cookie头 final cookie = response.headers['set-cookie']; if (cookie != null) { // 将Cookie注入WebView await controller.runJavaScript('document.cookie = "$cookie";'); } // 直接加载页面,WebView会自动携带Cookie await controller.loadRequest(Uri.parse('${Config.domain}/mobile_index.php')); }
说明
- 方案一完全遵循官方替代方案的思路,无需修改服务器逻辑,适配性强。
- 方案二直接利用原生Android能力,避免
loadHtmlString带来的资源加载问题,但需针对平台做适配。 - 方案三需服务器支持Cookie认证,适合原本就用Cookie做会话管理的场景。
内容的提问来源于stack exchange,提问作者Nate Perdomo
相关产品推荐
相关产品推荐

