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

如何在Flutter/Ionic的Webview中监听HTTP请求并获取POST载荷?

监听Flutter/Ionic WebView内的HTTP请求(无需修改源HTML)

Flutter 实现方式

要捕获WebView内的POST请求载荷,无需修改源HTML的核心思路是在页面加载完成后注入JavaScript脚本,拦截XMLHttpRequest和Fetch API的调用,再通过Flutter的JavaScriptChannel将数据回传到原生层。

代码示例

使用webview_flutter插件实现:

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class RequestCapturingWebView extends StatefulWidget {
  final String targetUrl;
  const RequestCapturingWebView({super.key, required this.targetUrl});

  @override
  State<RequestCapturingWebView> createState() => _RequestCapturingWebViewState();
}

class _RequestCapturingWebViewState extends State<RequestCapturingWebView> {
  late final WebViewController _webController;

  @override
  void initState() {
    super.initState();
    _webController = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      // 创建JS通信通道,用于接收WebView传来的请求数据
      ..addJavaScriptChannel(
        'RequestCaptureChannel',
        onMessageReceived: (JavaScriptMessage message) {
          // 解析捕获到的请求数据,这里可以对接你的注册逻辑
          final requestData = message.message;
          print('捕获到POST请求数据: $requestData');
          // 示例:解析JSON提取载荷
          // final payload = jsonDecode(requestData)['payload'];
        },
      )
      ..loadRequest(Uri.parse(widget.targetUrl))
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageFinished: (String url) {
            // 页面加载完成后注入监听脚本
            _webController.runJavaScript('''
              // 拦截XMLHttpRequest的open和send方法
              const originalXHRopen = XMLHttpRequest.prototype.open;
              XMLHttpRequest.prototype.open = function(method, url) {
                this.addEventListener('load', () => {
                  if (method.toUpperCase() === 'POST') {
                    const payload = this.__requestData || '无请求体';
                    window.RequestCaptureChannel.postMessage(JSON.stringify({
                      method,
                      url,
                      payload,
                      response: this.responseText,
                      type: 'xhr'
                    }));
                  }
                });
                return originalXHRopen.apply(this, arguments);
              };

              const originalXHRsend = XMLHttpRequest.prototype.send;
              XMLHttpRequest.prototype.send = function(data) {
                this.__requestData = data;
                return originalXHRsend.apply(this, arguments);
              };

              // 拦截Fetch API
              const originalFetch = window.fetch;
              window.fetch = function(input, init) {
                const method = (init?.method || 'GET').toUpperCase();
                const requestUrl = typeof input === 'string' ? input : input.url;
                if (method === 'POST') {
                  const payload = init?.body || '无请求体';
                  // 请求发送前捕获数据
                  window.RequestCaptureChannel.postMessage(JSON.stringify({
                    method,
                    url: requestUrl,
                    payload,
                    timing: 'beforeSend',
                    type: 'fetch'
                  }));
                }
                // 请求完成后捕获响应
                return originalFetch.apply(this, arguments).then(response => {
                  response.clone().text().then(body => {
                    window.RequestCaptureChannel.postMessage(JSON.stringify({
                      method: (init?.method || 'GET').toUpperCase(),
                      url: requestUrl,
                      response: body,
                      timing: 'afterSend',
                      type: 'fetch'
                    }));
                  });
                  return response;
                });
              };
            ''');
          },
        ),
      );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('WebView请求监听')),
      body: WebViewWidget(controller: _webController),
    );
  }
}

Ionic 实现方式

Ionic(无论用Capacitor还是Cordova)同样可以通过注入JS脚本拦截请求,再通过原生桥接将数据传回应用。下面以Capacitor为例:

代码示例

import { Component, OnInit } from '@angular/core';
import { App, WebView } from '@capacitor/app';

@Component({
  selector: 'app-webview-capture',
  template: `
    <ion-header>
      <ion-toolbar>
        <ion-title>WebView请求捕获</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content>
      <capacitor-web-view [src]="targetUrl"></capacitor-web-view>
    </ion-content>
  `,
})
export class WebviewCapturePage implements OnInit {
  targetUrl = 'https://your-target-page.com';

  async ngOnInit() {
    const webView = await WebView.getWebView();

    // 页面加载完成后注入监听脚本
    webView.addListener('ionPageDidLoad', async () => {
      await webView.evaluateJavaScript(`
        // 拦截XMLHttpRequest
        const originalXHRopen = XMLHttpRequest.prototype.open;
        XMLHttpRequest.prototype.open = function(method, url) {
          this.addEventListener('load', () => {
            if (method.toUpperCase() === 'POST') {
              const payload = this.__requestData || '无请求体';
              // 通过Capacitor发送事件到原生
              window.Capacitor.App.fireNativeEvent('webviewRequestCaptured', {
                method, url, payload, response: this.responseText, type: 'xhr'
              });
            }
          });
          return originalXHRopen.apply(this, arguments);
        };

        const originalXHRsend = XMLHttpRequest.prototype.send;
        XMLHttpRequest.prototype.send = function(data) {
          this.__requestData = data;
          return originalXHRsend.apply(this, arguments);
        };

        // 拦截Fetch API
        const originalFetch = window.fetch;
        window.fetch = function(input, init) {
          const method = (init?.method || 'GET').toUpperCase();
          const requestUrl = typeof input === 'string' ? input : input.url;
          if (method === 'POST') {
            const payload = init?.body || '无请求体';
            window.Capacitor.App.fireNativeEvent('webviewRequestCaptured', {
              method, url: requestUrl, payload, timing: 'beforeSend', type: 'fetch'
            });
          }
          return originalFetch.apply(this, arguments).then(response => {
            response.clone().text().then(body => {
              window.Capacitor.App.fireNativeEvent('webviewRequestCaptured', {
                method: (init?.method || 'GET').toUpperCase(),
                url: requestUrl,
                response: body,
                timing: 'afterSend',
                type: 'fetch'
              });
            });
            return response;
          });
        };
      `);
    });

    // 监听原生事件,接收WebView传来的请求数据
    App.addListener('webviewRequestCaptured', (data: any) => {
      console.log('捕获到WebView请求:', data);
      // 对接你的注册逻辑,比如提取payload中的用户信息
    });
  }
}

关键安全提醒

你提到的安全风险确实需要重视:

  • 注入的监听脚本可能被页面内的恶意JS篡改,导致数据泄露或请求伪造,建议只监听可信域名的页面。
  • 捕获的POST载荷可能包含敏感信息(如密码、验证码),务必在应用端加密存储和传输,避免本地泄露。
  • 不要将捕获的数据用于非预期用途,严格遵循隐私合规要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:48:19