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

Flutter WebView中如何拦截请求后修改原请求的响应体(而非直接返回自定义响应)

Flutter WebView中如何拦截请求后修改原请求的响应体(而非直接返回自定义响应)

我完全懂你的需求——你不想直接返回一个自定义响应来“冒充”服务器内容,而是希望让原请求正常完成,拿到真实的服务器响应后,再对内容做修改,最后交给WebView渲染。刚好我之前也遇到过类似场景,用InAppWebView是可以实现的,下面给你具体方案:

核心思路:手动发起原请求,修改响应后返回

shouldInterceptRequest的设计就是让你接管请求处理流程,所以我们可以在这里手动发起和原请求完全一致的请求,拿到真实响应后修改内容,再封装成WebResourceResponse返回给WebView,这样就实现了“拦截后修改原响应”的效果。

具体代码实现

首先可以引入Dart自带的http包来处理请求,下面是完整的示例代码:

import 'package:http/http.dart' as http;
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

// ... 你的其他页面代码 ...

shouldInterceptRequest: (controller, request) async {
  // 只针对目标txt文件请求做处理
  if (request.url.rawValue.toString().endsWith(".txt")) {
    try {
      // 1. 复刻原请求的所有参数:URL、请求方法、Headers、Body
      final uri = request.url.toUri();
      http.BaseRequest httpRequest;
      
      // 根据原请求方法创建对应HTTP请求
      switch (request.method) {
        case "GET":
          httpRequest = http.Request('GET', uri);
          break;
        case "POST":
          httpRequest = http.Request('POST', uri);
          // 处理POST请求的body
          if (request.body != null) {
            (httpRequest as http.Request).bodyBytes = request.body!;
          }
          break;
        // 可根据需求扩展PUT、DELETE等其他方法
        default:
          httpRequest = http.Request(request.method, uri);
      }

      // 复制原请求的所有请求头
      request.headers.forEach((key, value) {
        httpRequest.headers[key] = value;
      });

      // 2. 发起请求,拿到服务器真实响应
      final httpResponse = await http.Client().send(httpRequest);
      final responseBytes = await httpResponse.stream.toBytes();
      final responseBody = String.fromCharCodes(responseBytes);

      // 3. 自定义修改响应内容的逻辑
      final modifiedBody = responseBody.replaceAll("原始文本内容", "替换后的自定义内容");
      final modifiedBytes = modifiedBody.codeUnits;

      // 4. 封装成WebView可识别的响应对象返回
      return WebResourceResponse(
        data: modifiedBytes,
        mimeType: httpResponse.headers['content-type'] ?? 'text/plain',
        encoding: httpResponse.headers['content-encoding'] ?? 'utf-8',
        statusCode: httpResponse.statusCode,
        reasonPhrase: httpResponse.reasonPhrase,
        headers: httpResponse.headers.map((key, value) => MapEntry(key, value.join(','))),
      );
    } catch (e) {
      // 请求出错时,返回null让WebView自动处理原请求
      return null;
    }
  }
  // 非目标请求直接放行,交给WebView正常处理
  return null;
}

补充:JavaScript注入方案(可选)

如果你更倾向用JS来修改响应,也可以尝试在页面加载时注入脚本,拦截fetch或XMLHttpRequest的响应:

onWebViewCreated: (controller) {
  webViewController = controller;
  // 注入本地JS文件拦截响应
  controller.injectJavaScriptFileFromAsset(assetFilePath: 'assets/intercept_response.js');
}

然后在assets/intercept_response.js中编写拦截逻辑:

// 拦截fetch请求
const originalFetch = window.fetch;
window.fetch = async (...args) => {
  const response = await originalFetch(...args);
  if (args[0].endsWith('.txt')) {
    const text = await response.text();
    const modifiedText = text.replaceAll("原始文本", "修改后的文本");
    // 返回修改后的新响应
    return new Response(modifiedText, {
      status: response.status,
      statusText: response.statusText,
      headers: response.headers,
    });
  }
  return response;
};

// 拦截XMLHttpRequest
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
  originalOpen.call(this, method, url);
  if (url.endsWith('.txt')) {
    const originalOnLoad = this.onload;
    this.onload = function() {
      this.responseText = this.responseText.replaceAll("原始文本", "修改后的文本");
      if (originalOnLoad) originalOnLoad.call(this);
    };
  }
};

不过这种方式调试起来确实麻烦,而且如果页面有CSP限制或者自定义了请求封装,可能会导致拦截失效,所以还是前面的shouldInterceptRequest方案更稳定可靠。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 09:53:08