flutter dio网络请求封装实现

微信扫一扫,分享到朋友圈

flutter dio网络请求封装实现

flutter dio网络请求封装实现

文章友情链接: https://juejin.im/post/6844904098643312648

Flutter项目中使用网络请求的方式大致可分为两种,分别是Dart原生的网络请求 HttpClient类以及第三方开源的网络请求库。在Dart社区开源的第三方http请求库中 Flutter中文网
开源的 Dio库
人气最高。

  下面我们先来比较下这两种网络请求方式,然后再看怎么基于 Dio库封装方便使用的网络请求工具类HttpManager。

网络请求库比较

HttClient类

Dart IO库中提供了用于发起Http请求的一些类,我们可以直接使用HttpClient来发起请求。

使用HttpClient发起请求共分为五步:

  1. 创建一个HttpClient
HttpClient httpClient = new HttpClient();
复制代码
  1. 打开Http连接,设置请求头
HttpClientRequest request = await httpClient.getUrl(uri);
复制代码

这一步可以使用任意Http Method,如httpClient.post(…)、httpClient.delete(…)等。如果包含Query参数,可以在构建uri时添加,如:

Uri uri=Uri(scheme: "https", host: "flutterchina.club", queryParameters: {
"xx":"xx",
"yy":"dd"
});
复制代码

通过HttpClientRequest可以设置请求header,如:

request.headers.add("user-agent", "test");
复制代码

如果是post或put等可以携带请求体方法,可以通过HttpClientRequest对象发送request body,如:

String payload="...";
request.add(utf8.encode(payload));
//request.addStream(_inputStream); //可以直接添加输入流
复制代码
  1. 等待连接服务器
HttpClientResponse response = await request.close();
复制代码

这一步完成后,请求信息就已经发送给服务器了,返回一个HttpClientResponse对象,它包含响应头(header)和响应流(响应体的Stream),接下来就可以通过读取响应流来获取响应内容。

  1. 读取响应内容
String responseBody = await response.transform(utf8.decoder).join();
复制代码

我们通过读取响应流来获取服务器返回的数据,在读取时我们可以设置编码格式,这里是utf8。

  1. 请求结束,关闭HttpClient
httpClient.close();
复制代码

关闭client后,通过该client发起的所有请求都会中止。

  以上的步骤是dart原生网络HttpClient使用方式,可以发现直接使用HttpClient发起网络请求是比较麻烦的,很多事情都得手动处理,如果再涉及到文件上传/下载、Cookie管理等就会变得非常繁琐,并且HttpClient本身功能较弱,很多常用功能都不支持。

Dio库

dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时等…

  1. pubspec.yaml 添加依赖

dependencies: dio: ^x.x.x #请使用pub上的最新版本

  1. 导入引用并创建dio 实例

import ‘package:dio/dio.dart’;

Dio dio = Dio();

接下来就可以通过 dio实例来发起网络请求了,注意,一个dio实例可以发起多个http请求,一般来说,APP只有一个http数据源时,dio应该使用单例模式。

  1. 发起网络请求

Get 请求

Response response;

response=await dio.get(“/test?id=12&name=cheney”)

print(response.data.toString());

Post请求

Response response;

response=await dio.post(“/test”,data:{“id”:12,”name”:”cheney”})

print(response.data.toString());

以上就是Dio库网络请求的基本使用,是不是很简单,除了这些基本的用法,dio还支持请求配置、拦截器等,官方资料比较详细,故在这里不再赘述,详情可以参考dio主页: github.com/flutterchin…

封装Dio工具类

为什么要封装 dio

做一些公共处理,方便灵活的使用。

做那些封装

  • 统一处理请求前缀;( www.xx.com/api/v1
    不用每个请求都加前缀)
  • 统一输出请求或响应信息;
  • 统一错误信息处理;
  • 兼容多种网络请求、支持文件上传、下载;
  • 支持同步回调与异步Future 两种形式
  • 返回数据自动转json格式并默认解析公共数据模型;

目录

类名 描述
HttpManager 网络请求管理类
HttpError 网络请求统一错误类
LogInterceptor 网络请求工具类

HttpManager

import 'dart:core';
import 'package:connectivity/connectivity.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_common_utils/http/http_error.dart';
import 'package:flutter_common_utils/log_util.dart';
///http请求成功回调
typedef HttpSuccessCallback<T> = void Function(dynamic data);
///失败回调
typedef HttpFailureCallback = void Function(HttpError data);
///数据解析回调
typedef T JsonParse<T>(dynamic data);
/// @desc  封装 http 请求
/// @time 2019/3/15 10:35 AM
/// @author Cheney
class HttpManager {
init                        : 初始化baseUrl,超时时间等
get                         : get请求同步回调
post                        : post请求同步回调
upload                      : 文件上传同步回调
download                    : 文件下载同步回调
getAsync                    : get 请求异步方式
postAsync                   : post 请求异步方式
uploadAsync                 : 文件上传异步方式
downloadAsync               : 文件下载异步方式
[...]
}

详细源码见最后

这里处理了网络连接判断、取消网络请求、默认的数据格式解析等。 默认解析的数据格式:

{
"data":{},
"statusCode":"0",
"statusDesc":"02032008:用户授信未通过",
"timestamp":1569206576392
}

大家可根据自己的需求更改成自己的数据格式处理

HttpError

import 'package:dio/dio.dart';
/// @desc  网络请求错误
/// @time 2019/3/20 10:02 AM
/// @author Cheney
class HttpError {
///HTTP 状态码
static const int UNAUTHORIZED = 401;
static const int FORBIDDEN = 403;
static const int NOT_FOUND = 404;
static const int REQUEST_TIMEOUT = 408;
static const int INTERNAL_SERVER_ERROR = 500;
static const int BAD_GATEWAY = 502;
static const int SERVICE_UNAVAILABLE = 503;
static const int GATEWAY_TIMEOUT = 504;
///未知错误
static const String UNKNOWN = "UNKNOWN";
///解析错误
static const String PARSE_ERROR = "PARSE_ERROR";
///网络错误
static const String NETWORK_ERROR = "NETWORK_ERROR";
///协议错误
static const String HTTP_ERROR = "HTTP_ERROR";
///证书错误
static const String SSL_ERROR = "SSL_ERROR";
///连接超时
static const String CONNECT_TIMEOUT = "CONNECT_TIMEOUT";
///响应超时
static const String RECEIVE_TIMEOUT = "RECEIVE_TIMEOUT";
///发送超时
static const String SEND_TIMEOUT = "SEND_TIMEOUT";
///网络请求取消
static const String CANCEL = "CANCEL";
String code;
String message;
HttpError(this.code, this.message);
HttpError.dioError(DioError error) {
message = error.message;
switch (error.type) {
case DioErrorType.CONNECT_TIMEOUT:
code = CONNECT_TIMEOUT;
message = "网络连接超时,请检查网络设置";
break;
case DioErrorType.RECEIVE_TIMEOUT:
code = RECEIVE_TIMEOUT;
message = "服务器异常,请稍后重试!";
break;
case DioErrorType.SEND_TIMEOUT:
code = SEND_TIMEOUT;
message = "网络连接超时,请检查网络设置";
break;
case DioErrorType.RESPONSE:
code = HTTP_ERROR;
message = "服务器异常,请稍后重试!";
break;
case DioErrorType.CANCEL:
code = CANCEL;
message = "请求已被取消,请重新请求";
break;
case DioErrorType.DEFAULT:
code = UNKNOWN;
message = "网络异常,请稍后重试!";
break;
}
}
@override
String toString() {
return 'HttpError{code: $code, message: $message}';
}
}

这里设置了多种错误的描述,大家可根据需求修改。

LogInterceptor

import 'package:dio/dio.dart';
import 'package:flutter_common_utils/log_util.dart';
void log2Console(Object object) {
LogUtil.v(object);
}
/// @desc  自定义日志拦截器
///@time 2019/3/18 9:15 AM
/// @author Cheney
class LogInterceptor extends Interceptor {
LogInterceptor({
this.request = true,
this.requestHeader = true,
this.requestBody = false,
this.responseHeader = true,
this.responseBody = false,
this.error = true,
this.logPrint = log2Console,
});
[...]
}

详细源码见最后

这里默认使用 LogUtl 输出日志,大家可根据需要换成自己的日志输出工具类

Step1: 初始化

//初始化 Http,
HttpManager().init(
baseUrl: Api.getBaseUrl(),
interceptors: [
HeaderInterceptor(),
LogInterceptor(),
],
);

Step2:创建网络请求

///同步回调模式
///get 网络请求
void _get(){
HttpManager().get(
url: "/app/info",
params: {"iouCode": iouCode},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: "tag",
);
}
///post 网络请求
void _post(){
HttpManager().post(
url: "/app/info",
data: {"iouCode": iouCode},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: "tag",
);
}
///下载文件
void _download(){
HttpManager().download(
url: "/app/download",
savePath: "/savePath",
onReceiveProgress: (int count, int total) {
},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: tag,
);
}
///上传文件
void _upload() async{
FormData data = FormData.fromMap({
"file": await MultipartFile.fromFile(path, filename: "$photoTime"),
});
HttpManager().upload(
url: "/app/upload",
data: data,
tag: "tag",
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
);
}
///异步模式
///get 请求
void _getAysnc() async{
String timestamp =
await HttpManager().getAsync(url: "/app/info", tag: "syncTime");
}
///post 请求
void _postAysnc() async{
await HttpManager().postAsync(
url: "app/info",
tag: "tag",
data: {
'bannerTypes': ["wealthBanner"],
},
jsonParse: (json) => Pager(json, (data) => ImageAd(data)))
}
///下载文件
void _downloadAsync() async{
await HttpManager().downloadAsync(
url: "/app/download",
savePath: "/savePath",
onReceiveProgress: (int count, int total) {
},
tag: "tag",
);
}
///上传文件
void _uploadAsync() async{
FormData data = FormData.fromMap({
"file": await MultipartFile.fromFile(path, filename: "$photoTime"),
});
await  HttpManager().uploadAsync(
url: "/app/upload",
data: data,
tag: "tag",
);
}

最后

  如果在使用过程遇到问题,欢迎下方留言交流。

   工具类库地址

文章友情链接: https://juejin.im/post/6844904098643312648

研究发现锻炼能迅速引发年轻人的神经元效应 改善记忆力和学习能力

上一篇

美团王兴:北京是全中国最适合创业的城市 来这就成功了三分之一

下一篇

你也可能喜欢

flutter dio网络请求封装实现

长按储存图像,分享给朋友