如何使用 webview_flutter 在 Android 中的 POST 请求中发送自定义标头

问题描述 投票:0回答:1

这个文档指出它无法完成,所以我正在寻找替代解决方案:

目前,Android 不支持在使用 WebViewController 的 loadRequest 方法发出 POST 请求时设置自定义标头。如果您需要此功能,解决方法是手动发出请求,然后使用 loadHtmlString 加载响应数据。

他们提供的解决方法也有其自身的问题。 loadHtmlString 方法仅在 webview 元素中显示无样式、无响应的页面,并出现以下控制台错误:

I/chromium(19539): [INFO:CONSOLE(286)] "Uncaught ReferenceError: $ is not defined", source: about:blank (286)
I/chromium(19539): [INFO:CONSOLE(636)] "Uncaught ReferenceError: jQuery is not defined", source: about:blank (636)

这是我的 loadHtmlString 版本的实现。我尝试加载 jQuery 来解决无响应问题,但我没有与被忽略的样式表相关的消息:

class _PortalWebviewState extends State<PortalWebview> {
  late final WebViewController controller;

  @override
  void initState() {
    super.initState();
    controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted);
    _loadRequestWithAuthHeader();
    controller.addJavaScriptChannel(
      'Flutter',
      onMessageReceived: (JavaScriptMessage message) {
        print('JavaScript Error: ${message.message}');
     },
   );
  }

  Future<void> injectJQuery() async {
  await controller.runJavaScript('''
    var script = document.createElement('script');
    script.src = 'https://code.jquery.com/jquery-3.6.0.min.js';
    script.type = 'text/javascript';
    document.getElementsByTagName('head')[0].appendChild(script);
    ''');
  }

  Future<void> _loadRequestWithAuthHeader() async {
    const storage = FlutterSecureStorage();
    final token = await storage.read(key: 'token');
    if (token != null) {
      print("Token found in keychain.");
      final url = Uri.parse('${Config.domain}/mobile_index.php');
      final headers = {
        'Authorization': 'Bearer $token',
        'Content-Type': 'application/json',
      };

      try {
        final response = await http.post(url, headers: headers);
        print('Portal response status code: ${response.statusCode}');

        if (response.statusCode == 200) {
          await injectJQuery();
          await controller.loadHtmlString(response.body);
        } else {
          print('Error: ${response.statusCode}');
          // Handle error cases here
        }
      } catch (e) {
        print('Error: $e');
        // Handle exceptions here
      }
    } else {
      print('Token not found');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: true,
      appBar: AppBar(
        title: const Text('COMPANY NAME'),
        actions: [
          NavigationControls(controller: controller),
          // Menu(controller: controller),
        ],
      ),
      body: PortalWebviewStack(controller: controller),
    );
  }

它返回无样式的 HTML,其中包含加载空白页面的损坏链接 - 我的服务器日志不显示单击 Web 视图中的链接后收到任何请求。

我相信将 auth 标头作为 GET 请求的一部分发送可能是一个更简单的解决方案,但我喜欢 POST 的安全性,并且相信这种解决方法在我的用例中应该是可能的,因为它在上面的文档和 this 中被引用Github问题。

android flutter webview-flutter
1个回答
0
投票

我决定使用 LoadRequestMethod.get 来跳过 Android 自定义 POST 标头限制:

class _InvoiceWebviewState extends State<InvoiceWebview> {
  late final WebViewController controller;

  @override
  void initState() {
    super.initState();
    controller = WebViewController();
    _loadRequestWithAuthHeader();
  }

  Future<void> _loadRequestWithAuthHeader() async {
    const storage = FlutterSecureStorage();
    final token = await storage.read(key: 'token');

    if (token != null) {
      final headers = {'Authorization': 'Bearer $token'};

      await controller.loadRequest(
        Uri.parse('${Config.domain}/invoices/new'),
        method: LoadRequestMethod.get,
        headers: headers,
      );
    } else {
      print('Token not found');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: true,
      appBar: AppBar(
        title: const Text('COMPANY NAME'),
        actions: [
          NavigationControls(controller: controller),
          // Menu(controller: controller),
        ],
      ),
      body: InvoiceWebviewStack(controller: controller),
    );
  }
}

我放弃了自定义 POST 标头,因为使用

loadHtmlString
需要重新格式化我的 CSS 设置并解决 jQuery 问题。相反,我在 GET 请求中发送授权标头。标头在查询字符串中不可见,我仍然受益于 https 加密,最重要的是,它适用于 iOS 和 Android。

© www.soinside.com 2019 - 2024. All rights reserved.