Flutter Dio包網絡請求抓包解決方案

在Flutter中進行網絡請求時,咱們能夠使用的庫有3個,即Http請求庫、HttpClient請求庫和Dio請求庫(詳細介紹請參考:Flutter開發之Http網絡請求),使用得最多的就是Dio請求庫。由於相比Http請求庫和HttpClient請求庫,Dio庫不只支持常見的網絡請求,還支持Restful API、FormData、攔截器、請求取消、Cookie管理、文件上傳/下載、超時等操做。android

不過,默認狀況下,Dio進行網絡請求時是不支持抓包的,因此若是要進行抓包,就須要對Dio進行請求封裝,並編寫代理代碼。下面是代理的幾種寫法:ios

方法一

咱們能夠直接在Dio裏面設置ip以及端口,經過硬編碼的方式進行代理,代碼以下:json

(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
          (client) {
        //這一段是解決安卓https抓包的問題
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) {
          return Platform.isAndroid;
        };
        client.findProxy = (uri) {
          return "PROXY 代理ip:代理port";
        };
      };

不過,這種硬編碼方式,寫得太死,不夠靈活,每次更改代理都須要打包。網絡

方法二

直接在原生插件獲取手代理ip和代理端口,不過Android比較難,下面是iOS的實現。app

//自動獲取手機代理
  NSDictionary *proxySettings = (__bridge NSDictionary *)(CFNetworkCopySystemProxySettings());
           NSArray *proxies = (__bridge NSArray *)(CFNetworkCopyProxiesForURL((__bridge CFURLRef _Nonnull)([NSURL URLWithString:call.arguments]), (__bridge CFDictionaryRef _Nonnull)(proxySettings)));
           NSString *hostName = proxySettings[@"HTTPSProxy"];
           NSString *portName = [NSString stringWithFormat:@"%@",proxySettings[@"HTTPPort"]];
           long HTTPEnable = [proxySettings[@"HTTPEnable"] longValue];
           if (HTTPEnable==0) {
               hostName = @"";
           }

方法三

除了上面的硬編碼方式外,咱們還能夠採用scheme協議的方式傳入代理ip和代理端口。此方法的步驟以下:
1,註冊本身的URL Scheme,例如:scheme://
2,定義參數規則,例如:scheme://tiaoshi?host=10.0.206.163
3,引入flutter插件:uni_links: ^0.2.0
4,flutter監聽解析參數,並在dio裏面設置代理
5,使用[草料]https://cli.im生成一個二維碼:內容:scheme://tiaoshi?host=10.0.206.163
6,使用原生相機掃碼進入app就能夠抓包async

下面是涉及的代碼,Flutter代碼以下:post

Future<Null> initUniLinks() async {
   
    // 監聽插件scheme數據
      getLinksStream().listen((String link) {
        link =  Uri.decodeComponent(link);
        if(link.contains("scheme://")){
          String type = getTypeStr(link);
          String param = link.replaceAll("scheme://$type?", "");
          Map dict = getUrlParams(param);
          if(type=="tiaoshi"){//設置抓包代理
            String host = dict["host"];
            String port = dict["port"];
            //這裏是網絡請求封裝
            Net.setHttpProxy(host,port==null?"8888":port);
           }
        }
      // Parse the link and warn the user, if it is not correct
    }, onError: (err) {
      // Handle exception by warning the user their action did not succeed
    });
  }

//獲取scheme 要處理的業務類型
  String getTypeStr(String link){
    List params = link.split("?");
    String typeStr = params[0];
    typeStr =  typeStr.replaceAll("scheme://", "");
    return typeStr;
  }

//url參數轉map
  Map getUrlParams(String paramStr) {
    Map map = Map();
    List params = paramStr.split("&");
    for(int i=0;i<params.length;i++){
      String str = params[i];
      List arr = str.split("=");
      map[arr[0]]= arr[1];
    }
    return map;
  }

代理層代碼:編碼

static void setHttpProxy(String host,String port) {
    Application.httpProxy = host+':'+port;
    _initDio();
  }

static Future<void> _initDio() async {
    DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
    if (Platform.isAndroid) {
      _androidInfo = await deviceInfo.androidInfo;
    } else if (Platform.isIOS) {
      _iosInfo = await deviceInfo.iosInfo;
    }
    
    _dio = Dio(BaseOptions(
      contentType: 'application/json',
      baseUrl: Config.BASE_URL,
    ));
    _dio.options.receiveTimeout = 5000;
    _dio.options.connectTimeout = 10000;

    if (Application.httpProxy.length != 0) {
      (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
          (client) {
        //這一段是解決安卓https抓包的問題
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) {
          return Platform.isAndroid;
        };
       //這是抓包代理
        client.findProxy = (uri) {
          return "PROXY ${Application.httpProxy}";
        };
      };
    }
    _dio.interceptors.addAll([
      InterceptorsWrapper(
        onRequest: (Options options) {
          options.headers['DeviceName'] = 'xxxx';
          return options;
        },
        onResponse: (Response res) {
          try {

          ...

            return res;
          } catch (e) {
            return res;
          }
        },
        onError: (DioError e) {
          print(e);
         }
              break;
            default:
          }
          return e;
        },
      ),
    ]);
  }

static Future<ResponseModel> get(
    String path, {
    Map<String, dynamic> queryParameters,
    Options options,
    CancelToken cancelToken,
    void Function(int, int) onReceiveProgress,
  }) async {
    if (_dio == null) {
      await _initDio();
    }

    final res = await _dio.get<ResponseModel>(
      path,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onReceiveProgress: onReceiveProgress,
    );

    return res.data;
  }

  static Future<ResponseModel> post(
    String path, {
    dynamic data,
    Map<String, dynamic> queryParameters,
    Options options,
    CancelToken cancelToken,
    void Function(int, int) onSendProgress,
    void Function(int, int) onReceiveProgress,
  }) async {
    if (_dio == null) {
      await _initDio();
    }
    final res = await _dio.post<ResponseModel>(
      path,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );

    return res.data;
  }
相關文章
相關標籤/搜索