import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:gmalpha_flutter/commonModel/net/Api.dart'; import 'package:gmalpha_flutter/commonModel/toast/toast.dart'; const bool inProduction = const bool.fromEnvironment("dart.vm.product"); /// 返回 status code msg data. class BaseResp { String status; int code; String msg; T data; T extra; T userType; BaseResp( this.status, this.code, this.msg, this.data, this.extra, this.userType); @override String toString() { StringBuffer sb = new StringBuffer('{'); sb.write("\"status\":\"$status\""); sb.write(",\"code\":$code"); sb.write(",\"msg\":\"$msg\""); sb.write(",\"data\":\"$data\""); sb.write(",\"extra\":\"$extra\""); sb.write(",\"userType\":\"$userType\""); sb.write('}'); return sb.toString(); } } /// 返回 status code msg data Response. class BaseRespR { String status; int code; String msg; T data; T extra; T userType; Response response; BaseRespR(this.status, this.code, this.msg, this.data, this.extra, this.userType, this.response); @override String toString() { StringBuffer sb = new StringBuffer('{'); sb.write("\"status\":\"$status\""); sb.write(",\"code\":$code"); sb.write(",\"msg\":\"$msg\""); sb.write(",\"data\":\"$data\""); sb.write(",\"extra\":\"$extra\""); sb.write(",\"userType\":\"$userType\""); sb.write('}'); return sb.toString(); ; } } /// 请求方法. class Method { static final String get = "GET"; static final String post = "POST"; static final String put = "PUT"; static final String head = "HEAD"; static final String delete = "DELETE"; static final String patch = "PATCH"; } ///Http配置. class HttpConfig { /// constructor. HttpConfig({ this.status, this.code, this.msg, this.data, this.options, this.pem, this.pKCSPath, this.pKCSPwd, this.nativeCookie, }); /// BaseResp [String status]字段 key, 默认:status. String status; /// BaseResp [int code]字段 key, 默认:errorCode. String code; /// BaseResp [String msg]字段 key, 默认:errorMsg. String msg; /// BaseResp [T data]字段 key, 默认:data. String data; /// Options. BaseOptions options; /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. /// PEM证书内容. String pem; /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. /// PKCS12 证书路径. String pKCSPath; /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. /// PKCS12 证书密码. String pKCSPwd; //缓存 Map nativeCookie; } /// 单例 DioUtil. /// debug模式下可以打印请求日志. DioUtil.openDebug(). /// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). class DioUtil { static final DioUtil _instance = DioUtil._init(); static Dio _dio; /// BaseResp [String status]字段 key, 默认:status. String _statusKey = "status"; /// BaseResp [int code]字段 key, 默认:error = 0 代表成功. String _codeKey = "error"; /// BaseResp [String msg]字段 key, 默认:errorMsg. String _msgKey = "message"; /// BaseResp [T data]字段 key, 默认:data. String _dataKey = "data"; /// BaseResp [T data]字段 key, 默认:extra. String _extraKey = 'extra'; // BaseResp [T data]字段 key, 默认:user_type. String _userType = 'user_type'; /// Options. static BaseOptions _options = getDefOptions(); /// PEM证书内容. String _pem; /// PKCS12 证书路径. String _pKCSPath; /// PKCS12 证书密码. String _pKCSPwd; String _proxy = '172.30.9.117:8888'; static Map addHeadMap; /// 是否是debug模式. static bool _isDebug = !inProduction; static DioUtil getInstance() { return _instance; } factory DioUtil() { return _instance; } static var interceptor = InterceptorsWrapper(onRequest: (opt) { var headers = opt.headers; if (addHeadMap != null) { print("请求之前"); print("BASEURL!! ${opt.baseUrl}"); addHeadMap.forEach((k, v) { headers.putIfAbsent(k, () => v); print("HEADDD ${k} ${v}"); }); } }, onResponse: (response) { print("相应之前"); }, onError: (e) { print("网络错误 $e"); }); DioUtil._init() { _dio = new Dio(_options); _dio.interceptors.add(interceptor); } set addHead(Map map) { if (map != null) { addHeadMap = map; } } void setProxy(String proxy) { (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) { client.findProxy = (url) { return 'PROXY $proxy'; }; }; } /// set Config. void setConfig(HttpConfig config) { _statusKey = config.status ?? _statusKey; _codeKey = config.code ?? _codeKey; _msgKey = config.msg ?? _msgKey; _dataKey = config.data ?? _dataKey; _mergeOption(config.options); _mergeNativeCookie(config); _pem = config.pem ?? _pem; if (_dio != null) { _dio.options = _options; // (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) { // client.findProxy = (url) { // return _isDebug ? 'PROXY $_proxy' : 'DIRECT'; // }; // }; if (_pem != null) { // httpClientAdapter (_dio.httpClientAdapter as DefaultHttpClientAdapter) .onHttpClientCreate = (client) { client.badCertificateCallback = (X509Certificate cert, String host, int port) { if (cert.pem == _pem) { // 证书一致,则放行 return true; } return false; }; }; } if (_pKCSPath != null) { (_dio.httpClientAdapter as DefaultHttpClientAdapter) .onHttpClientCreate = (client) { SecurityContext sc = new SecurityContext(); //file为证书路径 sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); HttpClient httpClient = new HttpClient(context: sc); return httpClient; }; } } } /* * get请求 */ Future get(url, {data, options, cancelToken}) async { Response response; try { response = await _dio.get(url, queryParameters: data, options: options, cancelToken: cancelToken); // print('get success---------${response.statusCode}'); // print('get success---------${response.data}'); _printHttpLog(response); // response.data; 响应体 // response.headers; 响应头 // response.request; 请求体 // response.statusCode; 状态码 } on DioError catch (e) { print('get error---------$e'); formatError(e); } return response; } /* * post请求 */ Future post(url, {data, options, cancelToken}) async { Response response; try { response = await _dio.post(url, queryParameters: data, options: options, cancelToken: cancelToken); print('post success---------${response.statusCode} ${response.data}'); } on DioError catch (e) { print('post error---------$e'); formatError(e); } return response; } /* * 下载文件 */ downloadFile(urlPath, savePath) async { Response response; try { response = await _dio.download(urlPath, savePath, onReceiveProgress: (int count, int total) { //进度 print("$count $total"); }); print('downloadFile success---------${response.data}'); } on DioError catch (e) { print('downloadFile error---------$e'); formatError(e); } return response.data; } Future> requestR(String method, String path, {data, Options options, CancelToken cancelToken}) async { Response response = await _dio.request(path, data: data, options: _checkOptions(method, options), cancelToken: cancelToken); _printHttpLog(response); String _status; int _code; String _msg; T _data; T _extra; T _userType; _status = response.statusCode.toString(); if (response.statusCode == HttpStatus.ok || response.statusCode == HttpStatus.created) { try { if (response.data is Map) { _code = (response.data[_codeKey] is String) ? int.tryParse(response.data[_codeKey]) : response.data[_codeKey]; _msg = response.data[_msgKey]; _data = response.data[_dataKey]; } else { Map _dataMap = _decodeData(response); _code = (_dataMap[_codeKey] is String) ? int.tryParse(_dataMap[_codeKey]) : _dataMap[_codeKey]; _msg = _dataMap[_msgKey]; _data = _dataMap[_dataKey]; _extra = response.data[_extraKey]; _userType = response.data[_userType]; } return new BaseRespR( _status, _code, _msg, _data, _extra, _userType, response); } catch (e) { return new Future.error(new DioError( response: response, message: "data parsing exception...", type: DioErrorType.RESPONSE, )); } } else { _code = 1; _msg = '请求失败'; } return new Future.error(new DioError( response: response, message: "statusCode: $response.statusCode, service error", type: DioErrorType.RESPONSE, )); } void formatError(DioError e) { String reason = ""; if (e.type == DioErrorType.CONNECT_TIMEOUT) { // It occurs when url is opened timeout. print("连接超时"); reason = "连接超时 ${e.message}"; } else if (e.type == DioErrorType.SEND_TIMEOUT) { // It occurs when url is sent timeout. print("请求超时"); reason = "请求超时 ${e.message}"; } else if (e.type == DioErrorType.RECEIVE_TIMEOUT) { //It occurs when receiving timeout print("响应超时"); reason = "响应超时 ${e.message}"; } else if (e.type == DioErrorType.RESPONSE) { // When the server response, but with a incorrect status, such as 404, 503... print("出现异常"); reason = "出现异常 ${e.message}"; } else if (e.type == DioErrorType.CANCEL) { // When the request is cancelled, dio will throw a error with this type. print("请求取消"); reason = "请求取消 ${e.message}"; } else { //DEFAULT Default error type, Some other Error. In this case, you can read the DioError.error if it is not null. print("未知错误"); reason = "未知错误 ${e.message}"; } throw HttpException(reason); } Future download( String urlPath, savePath, { CancelToken cancelToken, data, Options options, }) { return _dio.download(urlPath, savePath, cancelToken: cancelToken, data: data, options: options); } /// decode response data. Map _decodeData(Response response) { if (response == null || response.data == null || response.data.toString().isEmpty) { return new Map(); } return json.decode(response.data.toString()); } /// check Options. Options _checkOptions(method, options) { if (options == null) { options = new Options(); } options.method = method; return options; } /// merge Option. void _mergeOption(BaseOptions opt) { _options.method = opt.method ?? _options.method; _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); _options.baseUrl = opt.baseUrl ?? _options.baseUrl; _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; _options.responseType = opt.responseType ?? _options.responseType; _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); _options.contentType = opt.contentType ?? _options.contentType; _options.validateStatus = opt.validateStatus ?? _options.validateStatus; _options.followRedirects = opt.followRedirects ?? _options.followRedirects; } void _mergeNativeCookie(HttpConfig config) { //合并native cookie if (config.nativeCookie == null) { return; } if (_options.headers == null) { _options.headers = Map(); } Map headers = _options.headers; headers['Cookie'] = config.nativeCookie['Cookie']; _options.headers = headers; print('cookie---------'); print(_options.headers); } void setCookie(String cookie) { if (_options.headers == null) { _options.headers = Map(); } Map headers = _options.headers; headers['Cookie'] = cookie; _options.headers = headers; print('cookie---------'); print(_options.headers); } /// print Http Log. void _printHttpLog(Response response) { if (!_isDebug) { return; } try { print("----------------Http Log----------------" + "\n[statusCode]: " + response.statusCode.toString() + "\n[request ]: " + _getOptionsStr(response.request)); _printDataStr("reqdata ", response.request.data); _printDataStr("response", response.data); } catch (ex) { print("Http Log" + " error......"); } } /// get Options Str. String _getOptionsStr(Options request) { return "method: " + request.method; } /// print Data Str. void _printDataStr(String tag, Object value) { String da = value.toString(); while (da.isNotEmpty) { if (da.length > 512) { print("[$tag ]: " + da.substring(0, 512)); da = da.substring(512, da.length); } else { print("[$tag ]: " + da); da = ""; } } } /// get dio. Dio getDio() { return _dio; } /// create new dio. static Dio createNewDio([Options options]) { Dio dio = new Dio(); return dio; } static String getBaseUrl() { // if (inProduction) { // //正式环境的 // return APP_HOST_RELEASE; // } else { // return APP_HOST_DEBUG; // } return APP_HOST_DEBUG; } /// get Def Options. static BaseOptions getDefOptions() { BaseOptions options = BaseOptions(); options.connectTimeout = 10 * 1000; options.receiveTimeout = 20 * 1000; // options.contentType = ContentType.parse('application/x-www-form-urlencoded'); options.contentType = ContentType.json; options.responseType = ResponseType.plain; // options.baseUrl = 'https://earth.iyanzhi.com/'; // options.baseUrl = 'http://earth.gmapp.env/'; options.baseUrl = getBaseUrl() + "/"; Map headers = Map(); headers['Accept'] = 'application/json'; headers['version'] = '1.0.0'; options.headers = headers; return options; } }