Flutter学习日记之Http&Dio网络请求的使用与封装
Posted Android_小黑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter学习日记之Http&Dio网络请求的使用与封装相关的知识,希望对你有一定的参考价值。
本文地址:https://blog.csdn.net/qq_40785165/article/details/117622514,转载需附上此地址
大家好,我是小黑,一个还没秃头的程序员~~~
人生的路无需苛求,只要你迈步,路就在你的脚下延伸。
今天分享的内容是Flutter中关于网络数据的请求–Http/Dio的使用,源码地址:https://gitee.com/fjjxxy/flutter-study.git,效果如下:
不管是开发pc端还是移动端,都免不了请求服务器接口,今天介绍的就是两种网络访问的库,访问https://pub.dev/搜索即可,数据接口使用的是玩Android 开放API
- Http
- Dio
(一)Http的使用
1.添加依赖,在pubspec.yaml文件中配置库的依赖
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for ios style icons.
cupertino_icons: ^0.1.3
http: ^0.13.3
2.引入
import 'package:http/http.dart' as http;
3.get请求
get方法的参数如下:
参数 | 说明 |
---|---|
url | 访问路径 |
headers | 请求头 |
以下是按钮点击进行get请求,代码如下:
TextButton(
onPressed:() async {
var url = Uri.parse(Api.MP_WECHAT_NAMES);
var response = await http.get(url,headers: {"token":""});
Toast.toast(context,
msg: jsonDecode(response.body.toString())["errorCode"] == 0
? "请求成功"
: "请求失败");
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
foregroundColor: MaterialStateProperty.all(Colors.white)),
child: Text("get请求"),
)
注:返回的数据是Json字符串,需要使用jsonDecode转换成Map
4.post请求
post方法的参数如下:
参数 | 说明 |
---|---|
url | 访问路径 |
headers | 请求头 |
body | 请求参数 |
encoding | 编码格式 |
这里按钮点击之后请求登录的接口,代码如下:
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
foregroundColor: MaterialStateProperty.all(Colors.white)),
onPressed: () async {
var url = Uri.parse(Api.LOGIN);
var response = await http.post(url,
body: {"username": "xiaohei", "password": "123456"});
Toast.toast(context,
msg: jsonDecode(response.body.toString())["errorCode"] == 0
? "请求成功"
: "请求失败");
},
child: Text("post请求"),
)
Http的使用就介绍到这里,接下来我们介绍Dio的使用以及封装
(二)Dio的使用
dio是一个自主的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义延迟等…
1.添加依赖
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
dio: ^4.0.0
2.引入
import 'package:dio/dio.dart';
3.get请求
get方法的参数如下:
参数 | 说明 |
---|---|
path | 请求路径 |
queryParameters | 请求体参数,类型是Map |
options | 可进行一些值的配置,比如连接超时时间,基本路径等 |
cancelToken | 用于取消请求,类型是CancelToken,同一个cancelToken的请求会都被取消掉 |
onReceiveProgress | 接收进度的监听 |
简单使用的代码如下:
response = await dio.get(url,
queryParameters: parameters ?? new Map<String, dynamic>(),
cancelToken: cancelToken);
4.post请求
post方法的参数如下:
参数 | 说明 |
---|---|
path | 请求路径 |
data | 请求体参数,类型是Map |
queryParameters | 请求体参数,类型是Map |
options | 可进行一些值的配置,比如连接超时时间,基本路径等 |
cancelToken | 用于取消请求,类型是CancelToken,同一个cancelToken的请求会都被取消掉 |
onReceiveProgress | 接收进度的监听 |
onSendProgress | 上传进度的监听 |
基本使用的代码如下:
response = await dio.post(url,
data: parameters ?? new Map<String, dynamic>(),
cancelToken: cancelToken);
5.上传多个文件
上传文件用的也是post方法,基本使用的代码如下:onSendProgress是上传进度的监听
uploadFiles(String url, List<String> list) async {
var formData = FormData.fromMap({
'files': list.map((e) {
return MultipartFile.fromFileSync(e,
filename: e.substring(e.indexOf("/")));
})
});
var response = await dio.post(url, data: formData,onSendProgress: (int sent, int total){
print('$sent $total');
});
return response.data;
}
上面使用FormData.fromMap创建文件数组会为key添加"[]",即文件数组的key为"files[]",这就是服务器端接收所判断的key,要想不自动加"[]",可以通过往FormData中添加MapEntry创建文件数组
uploadFiles2(String url, List<String> list,onSuccess, onError) async {
var formData = FormData();
list.map((e) {
formData.files.add(MapEntry(
'files',
MultipartFile.fromFileSync('./example/upload.txt',
filename: 'upload.txt'),
));
});
var response = await dio.post(url, data: formData,onSendProgress: (int sent, int total){
print('$sent $total');
});
return response.data;
}
6.下载文件
下载文件使用的是Dio的download方法,部分参数如下:
参数 | 说明 |
---|---|
urlPath | 下载的路径 |
savePath | 保存的路径 |
onReceiveProgress | 下载进度的监听 |
基本的使用代码如下:
downloadFile(urlPath, savePath, onReceiveProgress) async {
Response response;
try {
response = await dio.download(urlPath, savePath,
onReceiveProgress: onReceiveProgress);
} on DioError catch (e) {
//具体的错误类型可以自己处理
print(e.message);
}
return response.data;
}
Dio还提供了以下几个Api:
- Future put(…)
- Future delete(…)
- Future head(…)
- Future put(…)
- Future path(…)
- Future fetch(RequestOptions)
篇幅原因大家可以举一反三自己试试,以上那些Api都是一些Restful API,都是Future request() Api的别名
7.讲完了Api, 再介绍一下Dio怎么设置拦截器和公共配置的
已打印出请求信息为例,先定义一个拦截器,代码如下:
static InterceptorsWrapper interceptorsWrapper() {
return InterceptorsWrapper(onRequest: (options, handler) {
// Do something before request is sent
print(options.path);
print(options.queryParameters);
print(options.headers.toString());
return handler.next(options); //continue
}, onResponse: (response, handler) {
// Do something with response data
return handler.next(response); // continue
}, onError: (DioError e, handler) {
// Do something with response error
return handler.next(e); //continue
});
}
添加拦截器,代码如下:
mDio.interceptors.add(interceptorsWrapper());
添加公共配置,BaseOptions用来配置公共配置,而上面所列举出来的Api中的options参数是用来单独配置每次请求时的配置的,单独的配置可以覆盖公共配置,这里配置一些时间和默认的请求头,添加拦截器和配置的完整代码如下:
static Dio getDio() {
options = BaseOptions(
//请求基地址,可以包含子路径
baseUrl: Api.BASE_URL,
//连接服务器超时时间,单位是毫秒.
connectTimeout: 5000,
//2.x中为接收数据的最长时限
receiveTimeout: 3000,
//Http请求头.
headers: {"token": ""},
/ 请求的Content-Type,默认值是"application/json; charset=utf-8".
// /// 如果您想以"application/x-www-form-urlencoded"格式编码请求数据,
// /// 可以设置此选项为 `Headers.formUrlEncodedContentType`, 这样[Dio]
// /// 就会自动编码请求体.
contentType: Headers.jsonContentType,
/// [responseType] 表示期望以那种格式(方式)接受响应数据。
/// 目前 [ResponseType] 接受三种类型 `JSON`, `STREAM`, `PLAIN`.
///
/// 默认值是 `JSON`, 当响应头中content-type为"application/json"时,dio 会自动将响应内容转化为json对象。
/// 如果想以二进制方式接受响应数据,如下载一个二进制文件,那么可以使用 `STREAM`.
///
/// 如果想以文本(字符串)格式接收响应数据,请使用 `PLAIN`.
responseType: ResponseType.json,
);
mDio = Dio(options);
mDio.interceptors.add(interceptorsWrapper());
return mDio;
}
8.别忘了还要统一管理接口路径,代码如下:
class Api {
static final String BASE_URL = "https://www.wanandroid.com/";
static final String MP_WECHAT_NAMES = BASE_URL + "wxarticle/chapters/json";
static final String LOGIN = BASE_URL + "user/login";
}
(三)Dio的封装
上面Dio介绍的所有的Api都会返回一个Map类型或者字符串类型的response,但是每次都有自己去解析就很费事了,所以这里的封装就是为了将返回的数据自动转成自己想要的类型,方便直接调用里面的字段进行界面绘制,也要让这个请求自动进行成功回调以及失败回调。
1.json解析成dart class类(实体类)
这里的解析使用到的是FlutterJsonBeanFactory插件,在AndroidStudio-Settings-Plugins-Marketplace中下载插件后,在你想要创建文件的文件夹上右键-new-JsonToDartBeanAction,输入json数据和类名,点击"make",即可创建具有相应字段的类,如下图所示:
创建一个最外层的实体类,里面的data定义为泛型,可以将数据放进泛型中,最终解析成自己想要的实体类型,后面就方便调用字段了,BaseBean的代码如下:
class BaseBean<T> {
T data;
int errorCode;
String errorMsg;
BaseBean({this.data, this.errorCode, this.errorMsg});
BaseBean.fromJson(Map<String, dynamic> json) {
if (json['data'] != null && json['data'] != 'null') {
data = JsonConvert.fromJsonAsT<T>(json['data']);
}
errorCode = json['errorCode'];
errorMsg = json['errorMsg'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.data != null) {
data['data'] = this.data;
}
data['errorCode'] = this.errorCode;
data['errorMsg'] = this.errorMsg;
print(data is Map);
return data;
}
}
泛型解析的代码如下:
if (response.statusCode == 200) {
/// 将后台的data字段转成自己想要的数据/数据集,code根据后端实际返回进行判断访问结果
BaseBean<T> bean = BaseBean.fromJson(response.data);
if (bean.errorCode == 0 && onSuccess != null) {
/// 返回BaseBean,里面的data是自己想要的数据
onSuccess(bean);
} else {
onError(bean.errorMsg);
}
} else {
throw Exception('${response.statusCode}+${response.statusMessage}');
}
BaseBean.fromJson(Map<String, dynamic> json) {
if (json['data'] != null && json['data'] != 'null') {
data = JsonConvert.fromJsonAsT<T>(json['data']);
}
errorCode = json['errorCode'];
errorMsg = json['errorMsg'];
}
2.泛型解析介绍完了,封装工具类中其他的代码根据上面讲的那些Api的内容,相信大家都看得懂,这里就不再详细说明了,封装类HttpHelper 的完整代码如下:
import 'package:dio/dio.dart';
import 'Api.dart';
import 'BaseBean.dart';
class HttpHelper {
static Dio mDio;
static BaseOptions options;
static HttpHelper httpHelper;
CancelToken cancelToken = CancelToken();
static const String GET = 'get';
static const String POST = 'post';
static const String PUT = 'put';
static const String PATCH = 'patch';
static const String DELETE = 'delete';
static HttpHelper get instance => getInstance();
static Dio get dio => getDio();
static HttpHelper getInstance() {
if (null == httpHelper) httpHelper = HttpHelper();
return httpHelper;
}
static Dio getDio() {
options = BaseOptions(
//请求基地址,可以包含子路径
baseUrl: Api.BASE_URL,
//连接服务器超时时间,单位是毫秒.
connectTimeout: 10000,
//2.x中为接收数据的最长时限
receiveTimeout: 5000,
//Http请求头.
headers: {"token": ""},
/ 请求的Content-Type,默认值是"application/json; charset=utf-8".
// /// 如果您想以"application/x-www-form-urlencoded"格式编码请求数据,
// /// 可以设置此选项为 `Headers.formUrlEncodedContentType`, 这样[Dio]
// /// 就会自动编码请求体.
contentType: Headers.jsonContentType,
/// [responseType] 表示期望以那种格式(方式)接受响应数据。
/// 目前 [ResponseType] 接受三种类型 `JSON`, `STREAM`, `PLAIN`.
///
/// 默认值是 `JSON`, 当响应头中content-type为"application/json"时,dio 会自动将响应内容转化为json对象。
/// 如果想以二进制方式接受响应数据,如下载一个二进制文件,那么可以使用 `STREAM`.
///
/// 如果想以文本(字符串)格式接收响应数据,请使用 `PLAIN`.
responseType: ResponseType.json,
);
mDio = Dio(options);
mDio.interceptors.add(interceptorsWrapper());
return mDio;
}
static InterceptorsWrapper interceptorsWrapper() {
return InterceptorsWrapper(onRequest: (options, handler) {
// Do something before request is sent
print(options.path);
print(options.queryParameters);
print(options.headers.toString());
return handler.next(options); //continue
// 如果你想完成请求并返回一些自定义数据,你可以resolve一个Response对象 `handler.resolve(response)`。
// 这样请求将会被终止,上层then会被调用,then中返回的数据将是你的自定义response.
//
// 如果你想终止请求并触发一个错误,你可以返回一个`DioError`对象,如`handler.reject(error)`,
// 这样请求将被中止并触发异常,上层catchError会被调用。
}, onResponse: (response, handler) {
// Do something with response data
return handler.next(response); // continue
// 如果你想终止请求并触发一个错误,你可以 reject 一个`DioError`对象,如`handler.reject(error)`,
// 这样请求将被中止并触发异常,上层catchError会被调用。
}, onError: (DioError e, handler) {
// Do something with response error
return handler.next(e); //continue
// 如果你想完成请求并返回一些自定义数据,可以resolve 一个`Response`,如`handler.resolve(response)`。
// 这样请求将会被终止,上层then会被调用,then中返回的数据将是你的自定义response.
});
}
///Get请求
void getHttp<T>(
String url, {
parameters,
cancelToken,
Function(BaseBean<T> t) onSuccess,
Function(String error) onError,
}) async {
try {
getResponse<T>(url,
method: GET,
cancelToken: cancelToken,
parameters: parameters,
onSuccess: onSuccess,
onError: onError);
} catch (e) {
print(e以上是关于Flutter学习日记之Http&Dio网络请求的使用与封装的主要内容,如果未能解决你的问题,请参考以下文章
Flutter学习日记之表单组件Radio单选框&Checkbox复选框的使用
Flutter学习日记之实现上拉加载&下拉刷新的Listview
Flutter学习日记之实现上拉加载&下拉刷新的Listview