前面关于Flutter的讲解部分我把关于flutter的基础入门部分带着你们梳理了一遍,那从本篇博客开始,咱们开始进入新的领域,也算是给进阶篇开个头,今天咱们来一块学习一下Flutter中的网络请求库--->
Dio
,关于Flutter原生带的Http使用起来不论在功能上仍是扩展上都不是那么的强大,鉴于此笔者在这里推荐你们在项目中使用Dio
封装网络请求库。关于Http的使用读者可自行查阅资料学习。java
InterceptorsWrapper
拦截器1.1使用dio get请求一条json数据android
getRequest() async {
Response response = await Dio() .get('https://www.wanandroid.com/banner/json');
this.setState(() {
result= response.toString();
});
}
复制代码
1.2 利用dio post请求注册一个新用户git
postRequest() async {
var path = "https://www.wanandroid.com/user/register";
var params = {
"username": "aa112233",
"password": "123456",
"repassword": "123456"
};
Response response =
await Dio().post(path, queryParameters: params);
this.setState(() {
result= response.toString();
});
}
复制代码
因为简单的GET、跟POST请求操做起来比较简单,我就不单独附效果图跟讲解说明了,相信读者从开始看系列博客到如今,读懂上面的代码已经不在话下了,我把上面的get、跟post请求放到一张效果图上代码也贴到一块供你们读阅,另外感谢
玩安卓
提供的开放API做为本篇博客的请求测试用例。github
效果图 json
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
class NetWorkPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => PageState();
}
class PageState extends State<NetWorkPage> {
var resultJson = "";
@override
void initState() {
super.initState();
}
getRequest() async {
Response response = await Dio() .get('https://www.wanandroid.com/banner/json');
this.setState(() {
resultJson = response.toString();
});
}
postRequest() async {
var path = "https://www.wanandroid.com/user/register";
var params = {
"username": "aa112233",
"password": "123456",
"repassword": "123456"
};
Response response =
await Dio().post(path, queryParameters: params);
this.setState(() {
resultJson = response.toString();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Dio网络请求"),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
MaterialButton(
color: Colors.pinkAccent,
child: Text("GET 请求"),
onPressed: () {
getRequest();
}),
MaterialButton(
color: Colors.blueAccent,
child: Text("POST 请求"),
onPressed: () {
postRequest();
}),
Expanded(
child: Padding(
padding: EdgeInsets.all(20),
child: Center(
child: resultJson.length <= 0
? Text("数据加载中...")
: Text(
resultJson,
style: TextStyle(fontSize: 16),
),
),
))
],
),
);
}
}
复制代码
在项目开发过程当中随着项目越写越大,代码量也会成倍的增长,隔离业务抽取共性代码
的思想天然而然的出如今一个严于律己的开发者脑子里,特别是像网络请求这种操做,好的封装不只会减小冗余代码更能让代码层级变得清晰可读,下面笔者就带着本身的理解对Dio作一个简单封装,笔者自认为才疏学浅,代码中若有写的很差的地方还请各位不吝赐教。cookie
通常咱们在处理工具类时都会用到单例的思想,作为一个项目全局的网络请求工具类,咱们一样也把DioUtils
封装成单例模式网络
static DioUtils getInstance() {
if (_instance == null) {
_instance = new DioUtils();
}
return _instance;
}
复制代码
对于请求参数的初始化跟一些网络配置,Dio为开发者提供了BaseOptions、Options、RequestOptions可选Options配置,三者的优先级关系依次递增app
试想这样一个场景:通常咱们在对网络请求工具类设置参数,理论上是全局不能修改的,若是咱们的业务需求必须让咱们修改配置参数,好比基于不一样的接口服务须要设置不一样请求中的
header
内容,这个时候利用options的优先级咱们就能够很轻松的处理这个问题,稍后我会在代码里具体讲解async
先来看下BaseOptions给咱们提供的可供配置的参数:ide
BaseOptions({
String method,
int connectTimeout,
int receiveTimeout,
Iterable<Cookie> cookies,
this.baseUrl,
this.queryParameters,
Map<String, dynamic> extra,
Map<String, dynamic> headers,
ResponseType responseType = ResponseType.json,
ContentType contentType,
ValidateStatus validateStatus,
bool receiveDataWhenStatusError = true,
bool followRedirects = true,
int maxRedirects = 5,
RequestEncoder requestEncoder,
ResponseDecoder responseDecoder,
})
复制代码
上面构造方法中的属性读者基本都能见名知意作到自解释,我就不单独解释了,贴上一段我在代码里的配置:
//请求参数配置
_baseOptions = new BaseOptions(
baseUrl: BASE_URL,
//请求服务地址
connectTimeout: 5000,
//响应时间
receiveTimeout: 5000,
headers: {
//须要配置请求的header可在此处配置
},
//请求的Content-Type,默认值是[ContentType.json]. 也能够用ContentType.parse("application/x-www-form-urlencoded")
contentType: ContentType.json,
//表示指望以那种格式(方式)接受响应数据。接受三种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,
responseType: ResponseType.json,
);
复制代码
而后把_baseOptions
经过参数的形式传入Dio实例中完成配置的初始化
//建立dio实例
_dio = new Dio(_baseOptions);
复制代码
接下来我把咱们开篇用DIO作的简单GET、POST方法用咱们新写的工具类封装完成后从新作请求,让咱们来一块儿感觉下封装带来的便利。
封装GET请求
/** * get请求 */
get(url, {data, options, cancleToken}) async {
print('get request path ------${url}-------请求参数${data}');
Response response;
try {
response = await _dio.get(url,
queryParameters: data, options: options, cancelToken: cancleToken);
print('get success ---${response.data}');
} on DioError catch (e) {
print('请求失败---错误类型${e.type}');
}
return response.data;
}
复制代码
利用咱们封装好的get请求方法,开篇的get请求只需改成:
getRequest() async {
String result= await DioUtils().get('/banner/json');
this.setState(() {
resultJson = result;
});
}
复制代码
或者get的时候须要携带参数,例如以下这样一个请求
www.wanandroid.com/article/lis… 方法:GET 参数:cid 分类的id,上述二级目录的id
对上面的url进行分析
baseUrl
:www.wanandroid.com 咱们已经在工具类中初始化过了,因此不用设置path
: /article/list/0/json 咱们在get请求中须要传入的urldata
:cid=60 咱们封装好的get请求中对应的data数据
上述请求为:
getRequest() async {
var data = {
"cid": 60
};
String result = await DioUtils().get('/article/list/0/json', data: data);
this.setState(() {
resultJson = result;
});
}
复制代码
在刚刚讲BaseOptions时,咱们提到还有Options、RequestOptions可供配置,咱们提到能够利用Options的优先级从新覆盖掉原先在工具类里设置好的网络配置,好比修改提早在header中设置好的请求内容。 仍是上述代码,我先修改_baseOptions中的header的配置以下:
咱们利用Options修改BaseUrl后的请求url
_baseOptions = new BaseOptions(
baseUrl: BASE_URL,
connectTimeout: 5000,
receiveTimeout: 5000,
headers: {
//预设好的header信息
"testHeader":"bb"
},
contentType: ContentType.json,
responseType: ResponseType.json,
);
复制代码
仍是上述请求,如今咱们从新走一遍上述的get请求,看下log控制台打印的header信息
getRequest() async {
var data = {"cid": 60};
RequestOptions requestOptions = new RequestOptions(headers: {"testHeader":"aaaa"});
String result = await DioUtils() .get('/article/list/0/json', data: data,options: requestOptions);
this.setState(() {
resultJson = result;
});
}
复制代码
运行代码,再次执行get请求,控制台的header信息已经被咱们修改过了:
笔者只不过是借用这个例子让读者了解怎么去修改工具类里配置好的参数,经过RequestOptions不只仅是能够修改headerl
,基本你能在工具类设置的东西都能作修改,感兴趣的读者能够自行阅读源码测试,限于篇幅问题我这里就不展开讲解了。
POST请求封装 POST请求封装跟GET相似,这里我就不过多分析了,我直接贴源码了读者可结合代码自行对比差别
postRequest() async {
var params = {
"username": "aa112233",
"password": "123456",
"repassword": "123456"
};
String result = await DioUtils().post("/user/register",data: params);
this.setState(() {
resultJson = result;
});
}
复制代码
在DIo中咱们能够经过Interceptors
为咱们的网络请求添加拦截器
_dio.interceptors.add()
复制代码
咱们经过_dio.interceptors.add()
方法能够根据不一样业务为咱们的工具类添加不一样的拦截器,好比在网络请求开始以前,咱们给每一个请求都添加统一的token,或者userId,或者咱们能够对请求返回的数据作统一json格式化处理,对错误响应统一处理,这些业务场景均可以经过interceptors
来完成,好比下面个人配置:
//可根据项目须要选择性的添加请求拦截器
_dio.interceptors.add(
InterceptorsWrapper(onRequest: (RequestOptions requestions) async {
//此处可网络请求以前作相关配置,好比会全部请求添加token,或者userId
requestions.queryParameters["token"] = "testtoken123443423";
requestions.queryParameters["userId"] = "123456";
return requestions;
}, onResponse: (Response response) {
//此处拦截工做在数据返回以后,可在此对dio请求的数据作二次封装或者转实体类等相关操做
return response;
}, onError: (DioError error) {
//处理错误请求
return error;
}),
);
}
复制代码
如今咱们经过工具类进行的全部的网络请求的url后面都会被加入token=“testtoken123443423”&userId=123456这样两个参数,仍是上面的GET请求,下面咱们经过代码跟控制台的输出内容看下经过拦截器添加完通用参数的请求,log控制台打印的请求参数信息
getRequest() async {
var data = {"cid": 60};
String result = await DioUtils() .get('/article/list/0/json', data: data);
this.setState(() {
resultJson = result;
});
}
复制代码
cid = 60
的参数,可是经过控制台咱们已经清楚的看到token跟userId已经经过拦截器的被咱们添加到
queryParameters
里面了。
限于篇幅问题,封装好的DioUtils我就不贴出来了,附上源码的github地址,供读者参考,最后感谢玩安卓开放API平台提供的测试API用于本篇博客中的测试用例。