flutter dio网络请求封装实现
flutter dio网络请求封装实现
文章友情链接: https://juejin.im/post/6844904098643312648
下面我们先来比较下这两种网络请求方式,然后再看怎么基于 Dio库封装方便使用的网络请求工具类HttpManager。
网络请求库比较
HttClient类
Dart IO库中提供了用于发起Http请求的一些类,我们可以直接使用HttpClient来发起请求。
使用HttpClient发起请求共分为五步:
- 创建一个HttpClient
HttpClient httpClient = new HttpClient();
复制代码
- 打开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); //可以直接添加输入流
复制代码
- 等待连接服务器
HttpClientResponse response = await request.close();
复制代码
这一步完成后,请求信息就已经发送给服务器了,返回一个HttpClientResponse对象,它包含响应头(header)和响应流(响应体的Stream),接下来就可以通过读取响应流来获取响应内容。
- 读取响应内容
String responseBody = await response.transform(utf8.decoder).join();
复制代码
我们通过读取响应流来获取服务器返回的数据,在读取时我们可以设置编码格式,这里是utf8。
- 请求结束,关闭HttpClient
httpClient.close();
复制代码
关闭client后,通过该client发起的所有请求都会中止。
以上的步骤是dart原生网络HttpClient使用方式,可以发现直接使用HttpClient发起网络请求是比较麻烦的,很多事情都得手动处理,如果再涉及到文件上传/下载、Cookie管理等就会变得非常繁琐,并且HttpClient本身功能较弱,很多常用功能都不支持。
Dio库
dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时等...
- pubspec.yaml 添加依赖
dependencies: dio: ^x.x.x #请使用pub上的最新版本
- 导入引用并创建dio 实例
import 'package:dio/dio.dart';
Dio dio = Dio();
接下来就可以通过 dio实例来发起网络请求了,注意,一个dio实例可以发起多个http请求,一般来说,APP只有一个http数据源时,dio应该使用单例模式。
- 发起网络请求
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", );
}
最后
如果在使用过程遇到问题,欢迎下方留言交流。
flutter dio网络请求封装实现的更多相关文章
- Flutter -------- dio网络请求
dio是Flutter中文网开源的一个强大的Dart Http请求库,支持Restful API.FormData.拦截器.请求取消.Cookie管理.文件上传/下载.超时等... 1.添加依赖# d ...
- Flutter之网络请求
Flutter之网络请求 一,介绍与需求 1.1,介绍 1,http一个可组合的,基于Future的库,用于发出HTTP请求.包含一组高级功能和类,可轻松使用HTTP资源.它与平台无关,可以在命令行和 ...
- 【技术博客】Flutter—使用网络请求的页面搭建流程、State生命周期、一些组件的应用
Flutter-使用网络请求的页面搭建流程.State生命周期.一些组件的应用 使用网络请求的页面搭建流程 在开发APP时,我们常常会遇到如下场景:进入一个页面后,要先进行网络调用,然后使用调用返 ...
- React-Native 之 GD (八)GET 网络请求封装
1.到这里,相信各位对 React-Native 有所熟悉了吧,从现在开始我们要慢慢往实际的方向走,这边就先从网络请求这部分开始,在正式开发中,网络请求一般都单独作为一部分,我们在需要使用的地方只需要 ...
- 十. Axios网络请求封装
1. 网络模块的选择 Vue中发送网络请求有非常多的方式,那么在开发中如何选择呢? 选择一:传统的Ajax是基于XMLHttpRequest(XHR) 为什么不用它呢?非常好解释配置和调用方式等非常混 ...
- Flutter -------- Http库 网络请求封装(HttpController)
http库 再次封装的网络请求类 HttpController 1.添加依赖 dependencies: http: ^0.12.0 #latest version 2.导入库 import 'pac ...
- iOS开发——post异步网络请求封装
IOS中有许多网络请求的函数,同步的,异步的,通过delegate异步回调的. 在做一个项目的时候,上网看了很多别人的例子,发现都没有一个简单的,方便的异步请求的封装例子.我这里要给出的封装代码,是异 ...
- Android项目开发全程(三)-- 项目的前期搭建、网络请求封装是怎样实现的
在前两篇博文中已经做了铺垫,下面咱们就可以用前面介绍过的内容开始做一个小项目了(项目中会用到Afinal框架,不会用Afinal的童鞋可以先看一下上一篇博文),正所谓麻雀虽小,五脏俱全,这在里我会尽量 ...
- React Native 网络请求封装:使用Promise封装fetch请求
最近公司使用React作为前端框架,使用了异步请求访问,这里做下总结: React Native中虽然也内置了XMLHttpRequest 网络请求API(也就是俗称的ajax),但XMLHttpRe ...
随机推荐
- 2020-04-18:synchronized和reentrantLock的异同
福哥答案2020-04-19:采纳群员答案: 1 synchronized是关键字,reentrantlock是类,API层面的2 前者是通过monitor来实现锁机制,后者是基于AQS实现的,通过内 ...
- Vue 修饰符sync的应用
官方链接 https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-修饰符 这个解释有点不太直观,用代码解释一下 父组件 v-b ...
- 初始化vtable
在InstanceKlass::link_class_impl()方法中完成方法连接后会继续初始化vtable与itable,之前已经介绍过vtable与itable,并且在类解析过程中已经完成了大小 ...
- asp.net core mvc和angular项目的一些问题
最近公司布置任务,用asp.net core mvc和angular改写原来的一个用Silverlight做的项目.从来没搞过,找了两本书看了一天,又看了一天代码,大致心里有底了,就开始动手.没想到一 ...
- 一进“dos”就自动进入上次的目录
这个原来在别的地方发过,但是后来发现有bug,处理windows下带有空格的长文件夹会出错.因为原来那个帖子已经不能编辑了,所以修改后写在这里. 这里的“dos”,就是windows下的命令行窗口,所 ...
- 技术分享丨数据仓库的建模与ETL实践技巧
摘要:如何搭建数据仓库,在这个过程中都应该遵循哪些方法和原则,项目实践中有哪些技巧. 一.数据仓库的“心脏” 首先来谈谈数据模型.模型是现实世界特征的模拟和抽象,比如地图.建筑设计沙盘,飞机模型等等. ...
- 前端vue2-org-tree实现精美组织架构图
最近遇到开发组织架构的需求,与以往开发的组织架构不同,不光要展示人名,还要显示职务(或者子公司名称).对应的头像等,并且要考虑,如果用户未上传头像,需使用默认头像(男.女.中性),(⊙o⊙)…要尊重尊 ...
- 简单解析PAT、PMT的程序
刚开始学习有关TS.PAT.PMT方面的内容,参考了别人的一些程序,然后写了一个简单的解析TS的小程序.如果有地方错误,请发邮件给我843036544@qq.com. #include<stdi ...
- python基础 Day12
python Day12 生成器python社区,生成器与迭代器看成一种.生成器的本质就是迭代器. 区别:生成器是我们自己用python代码构建的数据结构.迭代器都是提供的,或者转化得来的. 获取生成 ...
- JavaFX桌面应用-loading界面
上次使用JavaFX开发了一个视频转码工具,当用户点击"启动"按钮开始转码的时候,会禁用启动按钮,防止多次启动转码. 这种处理方式对用户来说可能并是很友好,其实可以在启动转码的时弹 ...