zoukankan      html  css  js  c++  java
  • Flutter之网络请求

    Flutter之网络请求

    一,介绍与需求

    1.1,介绍

    1,http一个可组合的,基于Future的库,用于发出HTTP请求。包含一组高级功能和类,可轻松使用HTTP资源。它与平台无关,可以在命令行和浏览器上使用。

    2,Dart的功能强大的Http客户端,支持拦截器,全局配置,FormData,请求取消,文件下载,超时等。

    1.2,需求

    编写一个 App,最离不开的就是网络请求了。目前Flutter普及率也不是很高,网络请求大致分为如下三种方式:
    1. Dart 原生的网络请求 HttpClient
    2. 库 http
    3. Flutter中文网发布的 dio

    本文主要介绍后面两种网络请求方式的封装与使用,dart的原生网络请求HttpClient可参考文档通过HttpClient发起HTTP请求

    二,网络请求封装

    第一步:添加依赖

    打开 pubspec.yaml文件,在dependencies下添加如下包:

    1 http: ^0.12.0+2
    2 dio: ^3.0.4

    保存后,一般会自动下载包;如果没有自动下载可在项目根目录下运行如下命令,进行下载:

    1 flutter packages get

    2.1,http请求库

    第二步:引入包并创建网络请求类

    1 import 'package:http/http.dart' as http;
    1 class NetUtils {
    2 
    3 ...
    4 
    5 }

    第三步:get方式请求

     1 // get请求的封装,传入的两个参数分别是请求URL和请求参数,请求参数以map的形式传入,会在方法体中自动拼接到URL后面
     2   static Future<String> get(String url, {Map<String, String> params}) async {
     3     if (params != null && params.isNotEmpty) {
     4       // 如果参数不为空,则将参数拼接到URL后面
     5       StringBuffer sb = StringBuffer("?");
     6       params.forEach((key, value) {
     7         sb.write("$key" + "=" + "$value" + "&");
     8       });
     9       String paramStr = sb.toString();
    10       paramStr = paramStr.substring(0, paramStr.length - 1);
    11       url += paramStr;
    12     }
    13     http.Response res = await http.get(url, headers: getCommonHeader());
    14     return res.body;
    15   }

    第四步:POST方式请求

    1   // post请求
    2   static Future<String> post(String url, {Map<String, String> params}) async {
    3     http.Response res = await http.post(url, body: params, headers: getCommonHeader());
    4     print(res.statusCode);
    5     return res.body;
    6   }

    其他请求方式与post方式类似,这儿就不一一列举其他请求方式了。

    第五步:统一传参处理

    1   static Map<String, String> getCommonHeader() {
    2     Map<String, String> header = Map();
    3     header['yingqi'] = "jackson影琪";
    4     return header;
    5   }

    第六步:完整代码

     1 import 'dart:async';
     2 import 'package:http/http.dart' as http;
     3 
     4 class NetUtils {
     5   // get请求的封装,传入的两个参数分别是请求URL和请求参数,请求参数以map的形式传入,会在方法体中自动拼接到URL后面
     6   static Future<String> get(String url, {Map<String, String> params}) async {
     7     if (params != null && params.isNotEmpty) {
     8       // 如果参数不为空,则将参数拼接到URL后面
     9       StringBuffer sb = StringBuffer("?");
    10       params.forEach((key, value) {
    11         sb.write("$key" + "=" + "$value" + "&");
    12       });
    13       String paramStr = sb.toString();
    14       paramStr = paramStr.substring(0, paramStr.length - 1);
    15       url += paramStr;
    16     }
    17     http.Response res = await http.get(url, headers: getCommonHeader());
    18     return res.body;
    19   }
    20 
    21   // post请求
    22   static Future<String> post(String url, {Map<String, String> params}) async {
    23     http.Response res = await http.post(url, body: params, headers: getCommonHeader());
    24     print(res.statusCode);
    25     return res.body;
    26   }
    27 
    28  // put请求
    29   static Future<String> put(String url, {Map<String, String> params}) async {
    30     http.Response res = await http.put(url, body: params, headers: getCommonHeader());
    31     return res.body;
    32   }
    33 
    34   static Map<String, String> getCommonHeader() {
    35     Map<String, String> header = Map();
    36     header['yingqi'] = "1";
    37     return header;
    38   }
    39 
    40 }

    2.2,Dio

    第二步:引入包并创建网络请求类

    1 import 'dart:async';
    2 import 'package:dio/dio.dart';
    3 
    4 class DioNetUtils {
    5 
    6 ...
    7 
    8 }

    第三步:初始化Dio

     1   static final DioNetUtils _singleton = DioNetUtils._init();
     2   static Dio _dio;
     3 
     4  DioNetUtils._init() {
     5     BaseOptions options = new BaseOptions(
     6       baseUrl: "http://192.168.1.19:8880",
     7       connectTimeout: 1000 * 1,
     8       receiveTimeout: 1000 * 2,
     9       //Http请求头.
    10       headers: {//可统一配置传参
    11         //do something
    12         "version": "1.0.0"
    13       },
    14       //请求的Content-Type,默认值是"application/json; charset=utf-8". 也可以用"application/x-www-form-urlencoded"
    15       // contentType: "application/json; charset=utf-8",
    16       //表示期望以那种格式(方式)接受响应数据。接受4种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,
    17       responseType: ResponseType.json,
    18     );
    19     _dio = Dio(options);
    20 
    21 }

    第四步:添加拦截器

     1  //添加拦截器
     2     _dio.interceptors
     3         .add(InterceptorsWrapper(onRequest: (RequestOptions options) {
     4       print("请求之前处理");
     5       return options; //continue
     6     }, onResponse: (Response response) {
     7       print("响应之前处理");
     8       print(options);
     9       return response; // continue
    10     }, onError: (DioError e) {
    11       print("错误之前提示");
    12       Response errorInfo = _dealErrorInfo(e);
    13       return errorInfo; //continue
    14     }));

    第五步:统一处理错误信息

     1  _dealErrorInfo(error) {
     2     print(error.type);
     3     // 请求错误处理
     4     Response errorResponse;
     5     if (error.response != null) {
     6       errorResponse = error.response;
     7     } else {
     8       errorResponse = new Response(statusCode: 201);
     9     }
    10     // 请求超时
    11     if (error.type == DioErrorType.CONNECT_TIMEOUT) {
    12      ShowToast.warning("网络请求超时,请稍后重试");
    13       errorResponse.statusCode = ResultCode.CONNECT_TIMEOUT;
    14     }
    15     // 请求连接超时
    16     else if (error.type == DioErrorType.RECEIVE_TIMEOUT) {
    17       ShowToast.warning("网络连接超时,请稍后重试");
    18       errorResponse.statusCode = ResultCode.RECEIVE_TIMEOUT;
    19     }
    20     // 服务器错误
    21     else if (error.type == DioErrorType.RESPONSE) {
    22      ShowToast.warning("服务器繁忙,请稍后重试");
    23       errorResponse.statusCode = ResultCode.RESPONSE;
    24     }
    25     // 一般服务器错误
    26     else {
    27       ShowToast.warning("网络连接不可用,请稍后重试1");
    28       errorResponse.statusCode = ResultCode.DEFAULT;
    29     }
    30     return errorResponse;
    31   }

    第六步:GET方式请求

     1   /// Make http request with options.
     2   /// [method] The request method.
     3   /// [path] The url path.
     4   /// [data] The request data
     5   /// [options] The request options.
     6   /// String 返回 json data .
     7   Future<Map> request<T>(
     8     String path, {
     9     String method = Method.get,
    10     String contentType= "application/json; charset=utf-8",
    11     queryParameters,
    12     Options options,
    13     // CancelToken cancelToken,
    14   }) async {
    15     print('path===' + path);
    16     Response response = await _dio.request(
    17         path,
    18         queryParameters: queryParameters,
    19         options: _checkOptions(method, contentType, options),
    20         // cancelToken: cancelToken,
    21       );
    22     _printHttpLog(response);
    23     if (response.statusCode == 200) {
    24       try {
    25         if (response.data is Map) {
    26           if (response.data["httpCode"] != 200) {
    27            ShowToast.warning(response.data["message"]);
    28             return new Future.error(new DioError(
    29               response: response,
    30               type: DioErrorType.RESPONSE,
    31             ));
    32           }
    33           // 由于不同的接口返回的格式不固定不规范,所以需要根据接口格式自定义.
    34           return response.data['data'];
    35         } else {
    36           if (response.data is List) {
    37             Map<String, dynamic> _dataMap = Map();
    38             _dataMap["data"] = response.data;
    39             return _dataMap;
    40           }
    41         }
    42       } catch (e) {
    43         ShowToast.warning("网络连接不可用,请稍后重试");
    44         return new Future.error(new DioError(
    45           response: response,
    46           // message: "data parsing exception...",
    47           type: DioErrorType.RESPONSE,
    48         ));
    49       }
    50     }
    51      ShowToast.warning("网络连接不可用,请稍后重试");
    52     return new Future.error(new DioError(
    53       response: response,
    54       type: DioErrorType.RESPONSE,
    55     ));
    56   }

    第七步:POST方式请求-json传值

     1  /// Make http request with options.
     2   /// [method] The request method.
     3   /// [path] The url path.
     4   /// [data] The request data
     5   /// [options] The request options.
     6   /// String 返回 json data .
     7   Future<Map> request<T>(
     8     String path, {
     9     String method = Method.get,
    10     String contentType= "application/json; charset=utf-8",
    11     queryParameters,
    12     Options options,
    13     // CancelToken cancelToken,
    14   }) async {
    15     print('path===' + path);
    16     Response response;
    17     if (method == Method.get) {
    18       //GET方式
    19 
    20      ...
    21 
    22     } else {
    23       //除GET的其他方式
    24       var requestData = queryParameters;
    25       response = await _dio.request(
    26         path,
    27         data: requestData,
    28         options: _checkOptions(method, contentType, options),
    29         // cancelToken: cancelToken,
    30       );
    31     }
    32 
    33     _printHttpLog(response);
    34     if (response.statusCode == 200) {
    35 
    36       ...
    37 
    38     }
    39    
    40     ...
    41 
    42   }

    第八步:POST方式请求-表单传值

    1       //if (contentType == 'application/x-www-form-urlencoded') {//表单方式
    2        var requestData = new FormData.fromMap({
    3           "name": "jackson影琪",
    4           "age": 25,
    5         });

    第九步:请求日志处理

     1  // print Http Log.
     2   void _printHttpLog(Response response) {
     3     print(!_isDebug);
     4     if (!_isDebug) {
     5       return;
     6     }
     7     try {
     8       print("----------------Http Log Start----------------" +
     9           _getOptionsStr(response.request));
    10       print(response);
    11       print("----------------Http Log end----------------");
    12     } catch (ex) {
    13       print("Http Log" + " error......");
    14     }
    15   }
    16 
    17   // get Options Str.
    18   String _getOptionsStr(RequestOptions request) {
    19     return "method: " +
    20         request.method +
    21         "  baseUrl: " +
    22         request.baseUrl +
    23         "  path: " +
    24         request.path;
    25   }

    第10步:完整代码

      1 import 'dart:async';
      2 import 'package:dio/dio.dart';
      3 import 'ShowToastUtils.dart';
      4 
      5 class DioNetUtils {
      6   static final DioNetUtils _singleton = DioNetUtils._init();
      7   static Dio _dio;
      8 
      9   /// 是否是debug模式.
     10   static bool _isDebug = true;
     11 
     12   /// 打开debug模式.
     13   static void openDebug() {
     14     _isDebug = true;
     15   }
     16 
     17   DioNetUtils._init() {
     18     BaseOptions options = new BaseOptions(
     19       baseUrl: "http://192.168.1.19:8880",
     20       connectTimeout: 1000 * 1,
     21       receiveTimeout: 1000 * 2,
     22       //Http请求头.
     23       headers: {
     24         //do something
     25         "version": "1.0.0"
     26       },
     27       //请求的Content-Type,默认值是"application/json; charset=utf-8". 也可以用"application/x-www-form-urlencoded"
     28       // contentType: "application/json; charset=utf-8",
     29       //表示期望以那种格式(方式)接受响应数据。接受4种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,
     30       responseType: ResponseType.json,
     31     );
     32     _dio = Dio(options);
     33     //添加拦截器
     34     _dio.interceptors
     35         .add(InterceptorsWrapper(onRequest: (RequestOptions options) {
     36       print("请求之前处理");
     37       return options; //continue
     38     }, onResponse: (Response response) {
     39       print("响应之前处理");
     40       print(options);
     41       return response; // continue
     42     }, onError: (DioError e) {
     43       print("错误之前提示");
     44       Response errorInfo = _dealErrorInfo(e);
     45       return errorInfo; //continue
     46     }));
     47   }
     48 
     49   factory DioNetUtils() {
     50     return _singleton;
     51   }
     52 
     53   /// Make http request with options.
     54   /// [method] The request method.
     55   /// [path] The url path.
     56   /// [data] The request data
     57   /// [options] The request options.
     58   /// String 返回 json data .
     59   Future<Map> request<T>(
     60     String path, {
     61     String method = Method.get,
     62     String contentType= "application/json; charset=utf-8",
     63     queryParameters,
     64     Options options,
     65     // CancelToken cancelToken,
     66   }) async {
     67     print('path===' + path);
     68     Response response;
     69     if (method == Method.get) {
     70       //GET方式
     71       response = await _dio.request(
     72         path,
     73         queryParameters: queryParameters,
     74         options: _checkOptions(method, contentType, options),
     75         // cancelToken: cancelToken,
     76       );
     77     } else {
     78       //除GET的其他方式
     79       var requestData;
     80       print(contentType);
     81       if (contentType == 'application/x-www-form-urlencoded') {//表单方式
     82         requestData = new FormData.fromMap({
     83           "name": "jackson影琪",
     84           "age": 25,
     85         });
     86       }else{//json格式
     87          requestData = queryParameters;
     88       }
     89       response = await _dio.request(
     90         path,
     91         data: requestData,
     92         options: _checkOptions(method, contentType, options),
     93         // cancelToken: cancelToken,
     94       );
     95     }
     96 
     97     _printHttpLog(response);
     98     if (response.statusCode == 200) {
     99       try {
    100         if (response.data is Map) {
    101           if (response.data["httpCode"] != 200) {
    102            ShowToast.warning(response.data["message"]);
    103             return new Future.error(new DioError(
    104               response: response,
    105               type: DioErrorType.RESPONSE,
    106             ));
    107           }
    108           // 由于不同的接口返回的格式不固定不规范,所以需要根据接口格式自定义.
    109           return response.data['data'];
    110         } else {
    111           if (response.data is List) {
    112             Map<String, dynamic> _dataMap = Map();
    113             _dataMap["data"] = response.data;
    114             return _dataMap;
    115           }
    116         }
    117       } catch (e) {
    118         ShowToast.warning("网络连接不可用,请稍后重试");
    119         return new Future.error(new DioError(
    120           response: response,
    121           // message: "data parsing exception...",
    122           type: DioErrorType.RESPONSE,
    123         ));
    124       }
    125     }
    126      ShowToast.warning("网络连接不可用,请稍后重试");
    127     return new Future.error(new DioError(
    128       response: response,
    129       type: DioErrorType.RESPONSE,
    130     ));
    131   }
    132 
    133   /// check Options.
    134   Options _checkOptions(method, contentType, options) {
    135     if (options == null) {
    136       options = new Options();
    137     }
    138     // if (contentType) {
    139     //   //设置请求的类型 json 表单
    140     //   options.contentType = contentType;
    141     // }
    142     options.method = method;
    143     return options;
    144   }
    145 
    146   // print Http Log.
    147   void _printHttpLog(Response response) {
    148     print(!_isDebug);
    149     if (!_isDebug) {
    150       return;
    151     }
    152     try {
    153       print("----------------Http Log Start----------------" +
    154           _getOptionsStr(response.request));
    155       print(response);
    156       print("----------------Http Log end----------------");
    157     } catch (ex) {
    158       print("Http Log" + " error......");
    159     }
    160   }
    161 
    162   // get Options Str.
    163   String _getOptionsStr(RequestOptions request) {
    164     return "method: " +
    165         request.method +
    166         "  baseUrl: " +
    167         request.baseUrl +
    168         "  path: " +
    169         request.path;
    170   }
    171 
    172 // 错误全局处理
    173   _dealErrorInfo(error) {
    174     print(error.type);
    175     // 请求错误处理
    176     Response errorResponse;
    177     if (error.response != null) {
    178       errorResponse = error.response;
    179     } else {
    180       errorResponse = new Response(statusCode: 201);
    181     }
    182     // 请求超时
    183     if (error.type == DioErrorType.CONNECT_TIMEOUT) {
    184      ShowToast.warning("网络请求超时,请稍后重试");
    185       errorResponse.statusCode = ResultCode.CONNECT_TIMEOUT;
    186     }
    187     // 请求连接超时
    188     else if (error.type == DioErrorType.RECEIVE_TIMEOUT) {
    189       ShowToast.warning("网络连接超时,请稍后重试");
    190       errorResponse.statusCode = ResultCode.RECEIVE_TIMEOUT;
    191     }
    192     // 服务器错误
    193     else if (error.type == DioErrorType.RESPONSE) {
    194      ShowToast.warning("服务器繁忙,请稍后重试");
    195       errorResponse.statusCode = ResultCode.RESPONSE;
    196     }
    197     // 一般服务器错误
    198     else {
    199       ShowToast.warning("网络连接不可用,请稍后重试1");
    200       errorResponse.statusCode = ResultCode.DEFAULT;
    201     }
    202     return errorResponse;
    203   }
    204 }
    205 
    206 abstract class DioCallback<T> {
    207   void onSuccess(T t);
    208 
    209   void onError(DioError error);
    210 }

    ** dio网络请求失败的回调错误码 **

     1 /*
     2  * dio网络请求失败的回调错误码 自定义
     3  */
     4 class ResultCode {
     5   //正常返回是1
     6   static const SUCCESS = 1;
     7 
     8   //异常返回是0
     9   static const ERROR = 0;
    10 
    11   /// When opening  url timeout, it occurs.
    12   static const CONNECT_TIMEOUT = -1;
    13 
    14   ///It occurs when receiving timeout.
    15   static const RECEIVE_TIMEOUT = -2;
    16 
    17   /// When the server response, but with a incorrect status, such as 404, 503...
    18   static const RESPONSE = -3;
    19 
    20   /// When the request is cancelled, dio will throw a error with this type.
    21   static const CANCEL = -4;
    22 
    23   /// read the DioError.error if it is not null.
    24   static const DEFAULT = -5;
    25 }

    ** dio网络请求方式 **

    1 /// 请求方法.
    2 class Method {
    3   static const String get = "GET";
    4   static final String post = "POST";
    5   static final String put = "PUT";
    6   static final String head = "HEAD";
    7   static final String delete = "DELETE";
    8   static final String patch = "PATCH";
    9 }

    三,接口调用

    3.1,http请求库

    1,页面调用

     1  Map<String, String> params = Map();
     2       params['loginCode'] = _unameController.text;
     3       params['password'] = _pwdController.text;
     4  NetUtils.post(ServiceApi.loginAction, params: params).then((data) {
     5 print(ServiceApi.loginAction);
     6 print(data);
     7  }).catchError((e) {
     8         Toast.toast(
     9           context,
    10           msg: '网络请求出错:$e,请稍后重试!',
    11           position: 'top',
    12           bgColor: Color.fromRGBO(130, 0, 0, 1), // Color 提示框背景颜色
    13           textColor: Color.fromRGBO(250, 100, 100, 1), // Color 提示框文字颜色
    14         );
    15       });

    3.2,Dio

    1,服务接口地址

     1 import 'dart:async';
     2 
     3 import '../util/DioNetUtils.dart';
     4 
     5 class ServiceNetApi {
     6   ///获取用户信息
     7   Future<Map> getSingleDataById(data) async {
     8     return await DioNetUtils().request<String>(
     9       "/**/**/yingqi/**/getSingleDataById",
    10       queryParameters: data,
    11       method:Method.put
    12     );
    13   }
    14 }

    2,页面调用

     1   void getData() async {
     2       Map<String, String> params = Map();
     3       params['Id'] = "123456789";
     4       params['Name'] = "jackson影琪";
     5     await ServiceNetApi().getSingleDataById(params).then((json) {
     6        print('getSingleDataById');
     7       print(json);
     8     }).catchError((e) {
     9 
    10     });
    11   }

    3,返回的结果

    下一章->待定

  • 相关阅读:
    SpringBoot是如何动起来的
    Windows 10 安装 Docker for Windows
    Spring Boot2.0 设置拦截器
    修改博客园的css样式
    Spring-Aop
    Java自学-泛型 集合中的泛型
    Java自学-集合框架 聚合操作
    Java自学-集合框架 Comparator和Comparable
    Java自学-集合框架 hashCode原理
    Java自学-集合框架 HashSet、LinkedHashSet、TreeSet之间的区别
  • 原文地址:https://www.cnblogs.com/jackson-yqj/p/11769435.html
Copyright © 2011-2022 走看看