Flutter dio3.x上传文件(图片)具体实现

Dio3.0上传文件具体使用如下:

void uploadPhoto(File file) async{
    String path = file.path;
    var name = path.substring(path.lastIndexOf("/") + 1, path.length);
    String imageType = name.substring(name.lastIndexOf(".") + 1, name.length);
    var image = await MultipartFile.fromFile(
        path,
        filename: name,
    );
    print("文件路径="+path);
    print("文件名="+name);
    print("文件image=$image");
    FormData formData = FormData.fromMap({
      "image": image
    });
    asyncRequestNetwork<Map>(
      Method.post,
      url: HttpConstants.UPDATE_USER_PHOTO,
      params: formData,
      isList: false,
      isShow: true,
      onSuccess: (data){
        if(data != null) {
          String url = data["URL"];
          view.provider.setUserPhoto(url);
          UserInfoBean userInfoBean = Provider.of<UserProvider>(view.context).user;
          print("provider==="+userInfoBean.phone);
          userInfoBean.photoURI = url;
          Provider.of<UserProvider>(view.context).saveUser(userInfoBean);
        }
      },
    );
  }

封装dio请求dio_utils.dart

class DioUtils {

  static final DioUtils _singleton = DioUtils._internal();

  static DioUtils get instance => DioUtils();

  factory DioUtils() {
    return _singleton;
  }

  static Dio _dio;

  Dio getDio(){
    return _dio;
  }

  DioUtils._internal(){
    var options = BaseOptions(
      connectTimeout: 15000,
      receiveTimeout: 15000,
      responseType: ResponseType.plain,
      validateStatus: (status){
        // 不使用http状态码判断状态,使用AdapterInterceptor来处理(适用于标准REST风格)
        return true;
      },
    );
    _dio = Dio(options);
    /// Fiddler抓包代理配置 https://www.jianshu.com/p/d831b1f7c45b
//    (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
//        (HttpClient client) {
//      client.findProxy = (uri) {
//        //proxy all request to localhost:8888
//        return "PROXY 10.41.0.132:8888";
//      };
//      client.badCertificateCallback =
//          (X509Certificate cert, String host, int port) => true;
//    };
    /// 统一添加身份验证请求头
    _dio.interceptors.add(AuthInterceptor());
    /// 打印Log(生产模式去除)
    if (!Constant.inProduction){
      _dio.interceptors.add(LoggingInterceptor());
    }
    /// 适配数据(根据自己的数据结构,可自行选择添加)
    _dio.interceptors.add(AdapterInterceptor());
    ///cookie
    _dio.interceptors.add(CookieManager(
        PersistCookieJar(dir:StorageManager.cookieDirectory.path+"/.cookies/")));
  }

  // 数据返回格式统一,统一处理异常
  Future<BaseEntity<T>> _request<T>(String method, String url, {
    dynamic data, Map<String, dynamic> queryParameters,
    CancelToken cancelToken, Options options
  }) async {
    var response = await _dio.request(url, data: data, queryParameters: queryParameters, options: _checkOptions(method, options), cancelToken: cancelToken);
    try {
      /// 集成测试无法使用 isolate
      Map<String, dynamic> _map = Constant.isTest ? parseData(response.data.toString()) : await compute(parseData, response.data.toString());
      return BaseEntity.fromJson(_map);
    }catch(e){
      print(e);
      return BaseEntity(ExceptionHandle.parse_error, "网络错误,请重试!", null);
    }
  }

  Options _checkOptions(method, options) {
    if (options == null) {
      options = new Options();
    }
    options.method = method;
    return options;
  }

  Future requestNetwork<T>(Method method, String url, {
        Function(T t) onSuccess, 
        Function(List<T> list) onSuccessList, 
        Function(int code, String msg) onError,
        dynamic params, Map<String, dynamic> queryParameters, 
        CancelToken cancelToken, Options options, bool isList : false
  }) async {
    String m = _getRequestMethod(method);
    return await _request<T>(m, url,
        data: params,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken).then((BaseEntity<T> result){
      if (result.code == 200){
        if (isList){
          if (onSuccessList != null){
            onSuccessList(result.listData);
          }
        }else{
          if (onSuccess != null){
            onSuccess(result.data);
          }
        }
      }else{
        _onError(result.code, result.message, onError);
      }
    }, onError: (e, _){
      _cancelLogPrint(e, url);
      NetError error = ExceptionHandle.handleException(e);
      _onError(error.code, error.msg, onError);
    });
  }

  /// 统一处理(onSuccess返回T对象,onSuccessList返回List)
  asyncRequestNetwork<T>(Method method, String url, {
    Function(T t) onSuccess, 
    Function(List<T> list) onSuccessList, 
    Function(int code, String msg) onError,
    dynamic params, Map<String, dynamic> queryParameters, 
    CancelToken cancelToken, Options options, bool isList : false
  }){
    String m = _getRequestMethod(method);
    Observable.fromFuture(_request<T>(m, url, data: params, queryParameters: queryParameters, options: options, cancelToken: cancelToken))
        .asBroadcastStream()
        .listen((result){
          //print("@@@@@@@@"+result.message.toString());
      if (result.code == 200){
        if (isList){
          if (onSuccessList != null){
            onSuccessList(result.listData);
          }
        }else{
          if (onSuccess != null){
            //print("onSuccess=${result.data}");
            onSuccess(result.data);
          }
        }
      }else{
        _onError(result.code, result.message, onError);
      }
    }, onError: (e){
      _cancelLogPrint(e, url);
      NetError error = ExceptionHandle.handleException(e);
      _onError(error.code, error.msg, onError);
    });
  }

  _cancelLogPrint(dynamic e, String url){
    if (e is DioError && CancelToken.isCancel(e)){
      Log.i("取消请求接口: $url");
    }
  }

  _onError(int code, String msg, Function(int code, String mag) onError){
    if (code == null){
      code = ExceptionHandle.unknown_error;
      msg = "未知异常";
    }
    Log.e("接口请求异常: code: $code, msg: $msg");
    if (onError != null) {
      onError(code, msg);
    }
  }

  String _getRequestMethod(Method method){
    String m;
    switch(method){
      case Method.get:
        m = "GET";
        break;
      case Method.post:
        m = "POST";
        break;
      case Method.put:
        m = "PUT";
        break;
      case Method.patch:
        m = "PATCH";
        break;
      case Method.delete:
        m = "DELETE";
        break;
      case Method.head:
        m = "HEAD";
        break;
    }
    return m;
  }
}

Map<String, dynamic> parseData(String data){
  return json.decode(data);
}

enum Method {
  get,
  post,
  put,
  patch,
  delete,
  head
}

dio请求拦截器intercept.dart

class AuthInterceptor extends Interceptor{
  @override
  onRequest(RequestOptions options) {
    String dn = DeviceManager.getDeviceName();
    String dt = DeviceManager.getDeviceType();
    String av = DeviceManager.getAppVersion();
    String os = DeviceManager.getDeviceVersion();
    String rdi = "DT="+dt+";"+"DN="+dn+";"+"AV="+av+";"+"OS="+os;
    options.contentType = "application/x-www-form-urlencoded";
    options.headers = {"RDI":rdi};
    return super.onRequest(options);
  }
}


class LoggingInterceptor extends Interceptor{
  DateTime startTime;
  DateTime endTime;
  
  @override
  onRequest(RequestOptions options) {
    startTime = DateTime.now();
    Log.d("----------Start----------");
    Log.i("RequestUrl: " + options.baseUrl + options.path);
    Log.d("queryParameters: ${Transformer.urlEncodeMap(options.queryParameters)}");
    Log.d("RequestMethod: " + options.method);
    Log.d("RequestHeaders:" + options.headers.toString());
    //Log.d("RequestContentType: ${options.contentType}");
    //Log.d("RequestData: ${options.data.toString()}");
    return super.onRequest(options);
  }
  
  @override
  onResponse(Response response) {
    endTime = DateTime.now();
    int duration = endTime.difference(startTime).inMilliseconds;
    if (response.statusCode == ExceptionHandle.success){
      Log.d("ResponseCode: ${response.statusCode}");
    }else {
      Log.e("ResponseCode: ${response.statusCode}");
    }
    // 输出结果
    Log.json(response.data.toString());
    Log.d("----------End: $duration 毫秒----------");

    return super.onResponse(response);
  }
  
  @override
  onError(DioError err) {
    Log.d("----------Error-----------");
    return super.onError(err);
  }
}

class AdapterInterceptor extends Interceptor{

  static const String msg = "msg";
  static const String slash = "\"";
  static const String message = "message";

  static const String defaultText = "\"无返回信息\"";
  static const String notFound = "未找到查询信息";

  static const String failureFormat = "{\"code\":%d,\"message\":\"%s\"}";
  static const String successFormat = "{\"code\":0,\"data\":%s,\"message\":\"\"}";
  
  @override
  onResponse(Response response) {
    return super.onResponse(response);
  }
  
  @override
  onError(DioError err) {
    if (err.response != null){
      adapterData(err.response);
    }
    return super.onError(err);
  }

  Response adapterData(Response response){
    String result;
    String content = response.data == null ? "" : response.data.toString();
    /// 成功时,直接格式化返回
    if (response.statusCode == ExceptionHandle.success || response.statusCode == ExceptionHandle.success_not_content){
      if (content == null || content.isEmpty){
        content = defaultText;
      }
      result = sprintf(successFormat, [content]);
      response.statusCode = ExceptionHandle.success;
    }else{
      if (response.statusCode == ExceptionHandle.not_found){
        /// 错误数据格式化后,按照成功数据返回
        result = sprintf(failureFormat, [response.statusCode, notFound]);
        response.statusCode = ExceptionHandle.success;
      }else {
        if (content == null || content.isEmpty){
          // 一般为网络断开等异常
          result = content;
        }else {
          String msg;
          try {
            content = content.replaceAll("\\", "");
            if (slash == content.substring(0, 1)){
              content = content.substring(1, content.length - 1);
            }
            Map<String, dynamic> map = json.decode(content);
            if (map.containsKey(message)){
              msg = map[message];
            }else if(map.containsKey(msg)){
              msg = map[msg];
            }else {
              msg = "未知异常";
            }
            result = sprintf(failureFormat, [response.statusCode, msg]);
            // 401 token失效时,单独处理,其他一律为成功
            if (response.statusCode == ExceptionHandle.unauthorized){
              response.statusCode = ExceptionHandle.unauthorized;
            }else {
              response.statusCode = ExceptionHandle.success;
            }
          } catch (e) {
            Log.d("异常信息:$e");
            // 解析异常直接按照返回原数据处理(一般为返回500,503 HTML页面代码)
            result = sprintf(failureFormat, [response.statusCode, "服务器异常(${response.statusCode})"]);
          }
        }
      }
    }
    response.data = result;
    return response;
  }
}

由于使用了MVP的设计模式,所以进一步封装在了basePresenter中

void asyncRequestNetwork<T>(Method method, {@required String url, bool isShow : true, bool isClose: true, Function(T t) onSuccess, Function(List<T> list) onSuccessList, Function(int code, String msg) onError,
    dynamic params, Map<String, dynamic> queryParameters, CancelToken cancelToken, Options options, bool isList : false}){
    if (isShow) view.showProgress();
    DioUtils.instance.asyncRequestNetwork<T>(method, url,
        params: params,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken?? _cancelToken,
        isList: isList,
        onSuccess: (data){
          if (isClose) view.closeProgress();
          if (onSuccess != null) {
            onSuccess(data);
          }
        },
        onSuccessList: (data){
          if (isClose) view.closeProgress();
          if (onSuccessList != null) {
            onSuccessList(data);
          }
        },
        onError: (code, msg){
          _onError(code, msg, onError);
        }
    );
  }
   _onError(int code, String msg, Function(int code, String msg) onError){
    /// 异常时直接关闭加载圈,不受isClose影响
    view.closeProgress();
    if (code != ExceptionHandle.cancel_error){
      view.showToast(msg);
    }
    /// 页面如果dispose,则不回调onError
    if (onError != null && view.getContext() != null) {
      onError(code, msg);
    }
  }

你可能感兴趣的:(Flutter)