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

Flutter中Dio无法设置并使用代理发起网络请求问题排查

Flutter 代理请求失效问题解决指南

核心问题分析

你遇到的代理不生效问题,主要源于代码逻辑错误、环境变量配置缺失,以及代理设置的细节疏漏:

  1. 首次实现中连续调用dio.useProxy(),第二次调用直接覆盖了从代理池获取的有效代理;且dio.post()未加await导致请求未正确执行。
  2. 适配器方式设置代理时,存在变量作用域、代理格式校验、认证凭据初始化等问题。
  3. String.fromEnvironment('PROXY_URL')返回空,是因为未在运行/打包阶段传入该环境变量。

修复方案

一、Dio 基础代理设置(最简有效版)

修正代理覆盖问题,确保异步请求正确等待:

class DioProxiedPostRequest extends AbstractWebRequest {
  DioProxiedPostRequest(super.url, super.headers, super.body);

  @override
  Future<WebResponse> send() async {
    Proxy proxy = await ProxyGetter().getRandomProxy();
    String proxyUrl = "${proxy.getHost()}:${proxy.getPort()}";

    // 优先使用环境变量代理(如果配置)
    if (const bool.hasEnvironment('PROXY_URL')) {
      proxyUrl = const String.fromEnvironment('PROXY_URL');
    }

    Dio dio = Dio();
    dio.useProxy(proxyUrl);

    // 必须添加await等待请求完成
    Response response = await dio.post(
      url,
      data: json.encode(body),
      options: Options(headers: headers),
    );
    return DioWebResponse(url, response);
  }
}

二、DefaultHttpClientAdapter 进阶配置(支持代理认证)

如果需要更精细的代理控制(如证书忽略、代理认证),使用适配器方式:

@override
Future<WebResponse> send() async {
  Proxy proxy = await ProxyGetter().getRandomProxy();
  String proxyAddress = "${proxy.getHost()}:${proxy.getPort()}";

  // 环境变量代理优先级覆盖
  if (const bool.hasEnvironment('PROXY_URL')) {
    proxyAddress = const String.fromEnvironment('PROXY_URL');
  }

  Dio dio = Dio();
  (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
    // 按需开启:忽略自签名证书(仅Android端建议,iOS需额外配置)
    client.badCertificateCallback = (cert, host, port) => Platform.isAndroid;

    // 强制所有请求走代理
    client.findProxy = (url) => 'PROXY $proxyAddress';

    // 代理需要认证时添加凭据(无认证可删除此段)
    final proxyParts = proxyAddress.split(':');
    if (proxyParts.length == 2) {
      client.addProxyCredentials(
        proxyParts[0],
        int.parse(proxyParts[1]),
        'main',
        HttpClientBasicCredentials('代理用户名', '代理密码'),
      );
    }
    return client;
  };

  try {
    Response response = await dio.post(
      url,
      data: json.encode(body),
      options: Options(headers: headers),
    );
    return DioWebResponse(url, response);
  } catch (e) {
    // 代理连接失败时可添加重试逻辑
    rethrow;
  }
}

三、环境变量 PROXY_URL 配置方法

要让String.fromEnvironment('PROXY_URL')生效,需在运行/打包时传入参数:

  • 本地运行命令:
    flutter run --dart-define=PROXY_URL=xxx.xxx.xxx.xxx:xxxx
    
  • Android 打包命令:
    flutter build apk --dart-define=PROXY_URL=xxx.xxx.xxx.xxx:xxxx
    

四、http 包代理设置方法

如果需要使用原生http包,配置方式如下:

import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';

Future<http.Response> sendProxiedRequest(String url, Map<String, String> headers, Map<String, dynamic> body) async {
  Proxy proxy = await ProxyGetter().getRandomProxy();
  final proxyHost = proxy.getHost();
  final proxyPort = int.parse(proxy.getPort());

  final httpClient = HttpClient();
  httpClient.findProxy = (uri) => 'PROXY $proxyHost:$proxyPort';
  httpClient.badCertificateCallback = (cert, host, port) => Platform.isAndroid;

  final client = IOClient(httpClient);
  try {
    return await client.post(
      Uri.parse(url),
      headers: headers,
      body: json.encode(body),
    );
  } finally {
    client.close();
  }
}

额外注意事项

  • 免费代理池(如us-proxy.org)的代理可用性极低,建议添加代理预校验逻辑(比如请求httpbin.org/get验证返回的origin是否为代理IP)。
  • 即使使用代理,也需控制请求频率,避免触发目标网站的反爬机制。
  • iOS端忽略证书需在Info.plist中添加ATS配置,否则代理请求会被拦截。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 04:36:27