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

Flutter WebView添加Bearer授权请求头失败问题求助

解决Flutter WebView中Authorization Bearer请求头不生效的问题

我帮你捋一捋这个问题哈——你遇到的其实是WebView的一个常见坑:初始loadUrl传入的请求头只会对第一个请求生效,后续页面跳转、资源加载或者JS发起的请求都不会自动带上这个Authorization头,不管你用webview_flutter、flutter_webview_pro还是其他包,这个逻辑基本都是一致的。

核心解决方案:拦截所有请求,统一添加Authorization头

最可靠的做法是拦截WebView的所有导航请求,手动给每个请求带上Bearer令牌后再加载。下面以官方的webview_flutter包为例,给你修改代码:

import 'package:flutter/material.dart';
import 'package:skin_technology/core/consts/app_colors.dart';
import 'package:skin_technology/core/session_data/repo/session_data_service.dart';
import 'package:webview_flutter/webview_flutter.dart';

class CatalogWebView extends StatefulWidget {
  const CatalogWebView({Key? key}) : super(key: key);

  @override
  State<CatalogWebView> createState() => _CatalogWebViewState();
}

class _CatalogWebViewState extends State<CatalogWebView> {
  late WebViewController _webController;
  String? _authToken;

  @override
  void initState() {
    super.initState();
    // 提前获取令牌并保存到state中
    _fetchAuthToken();
  }

  Future<void> _fetchAuthToken() async {
    final sessionData = await SessionDataService.sessionData;
    setState(() {
      _authToken = sessionData?.token;
    });
  }

  // 封装带Authorization头的URL加载方法
  Future<void> _loadUrlWithAuth(String url) async {
    if (_authToken == null) return;
    
    final headers = {"Authorization": "Bearer $_authToken"};
    await _webController.loadRequest(
      WebRequest(
        uri: Uri.parse(url),
        headers: headers,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('КАТАЛОГ'),
        backgroundColor: AppColors.darkMainColor,
      ),
      body: _authToken == null
          ? const Center(child: CircularProgressIndicator())
          : WebView(
              javascriptMode: JavascriptMode.unrestricted,
              initialUrl: 'about:blank', // 先加载空白页,避免初始请求漏带头
              onWebViewCreated: (controller) async {
                _webController = controller;
                // 第一次加载目标页面
                await _loadUrlWithAuth('https://clubskt.ru/client/catalog');
              },
              navigationDelegate: (NavigationRequest request) {
                // 拦截所有导航请求,手动添加令牌后加载
                _loadUrlWithAuth(request.url);
                return NavigationDecision.prevent; // 阻止默认的无请求头加载
              },
            ),
    );
  }
}

为什么这个方案有效?

  1. 提前在initState中获取令牌并保存,避免在UI构建中重复异步请求
  2. 用navigationDelegate拦截所有页面跳转、新URL加载请求,确保每个请求都带上Authorization头
  3. 封装_loadUrlWithAuth方法,避免重复写请求头逻辑
  4. 初始加载空白页,确保第一次请求就带正确的令牌

备选方案:JavaScript注入(仅适用于AJAX请求)

如果你的页面主要是通过JS发起AJAX请求,也可以尝试注入JS来给所有XMLHttpRequest添加请求头,但这个方法无法覆盖页面跳转类的请求,所以只作为备选:

// 在WebView的onPageFinished回调中添加
onPageFinished: (url) {
  if (_authToken == null) return;
  _webController.runJavascript('''
    (function() {
      // 覆盖XMLHttpRequest的open方法,自动添加Authorization头
      const originalOpen = XMLHttpRequest.prototype.open;
      XMLHttpRequest.prototype.open = function(method, url) {
        this.setRequestHeader('Authorization', 'Bearer $_authToken');
        return originalOpen.apply(this, arguments);
      };
      // 如果页面用fetch API,也需要覆盖
      const originalFetch = window.fetch;
      window.fetch = function(resource, options = {}) {
        options.headers = {
          ...options.headers,
          'Authorization': 'Bearer $_authToken'
        };
        return originalFetch(resource, options);
      };
    })();
  ''');
}

额外注意事项

  • 确保服务器端允许跨域请求携带Authorization头(如果WebView加载的页面域名和API域名不同)
  • 测试时可以清除WebView缓存,避免旧的无请求头请求被缓存
  • 如果使用其他WebView包(如flutter_webview_pro),核心思路一致:找到请求拦截的回调,手动添加请求头后重新加载

内容的提问来源于stack exchange,提问作者Angelina Gromova

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 15:03:13