flutter简单封装属于自己的网络库
刚入坑flutter,虽然已经有更强大dio网络库了,但还是要学会自己封装一下,了解一下dart原生网络的实现
所谓自己动手,风衣足食,按照自己的代码习惯去做了个封装
Dart 没有像 Java 用单独的关键字 interface
来定义接口,用 class
声明的类或者用abstract
抽象类就可以是接口,然后可以通过关键字 implements
来实现一个或多个接口。但这种方式也有局限性,因为Dart不能创建内部类,有些时候我们要像java那样直接在一个方法内去实现一个接口的回调,又不想在当前类实现这个接口,例如在java下实现一个接口回调
HttpUtil.instance.get("https://www.baidu.com",new Callback(){
@override
void onFailure(int errCode, String errMsg) {
// TODO: implement onFailure
print(errMsg);
}
@override
void onResponse(String responseStr) {
// TODO: implement onResponse
print(responseStr);
}
});
我们可以通过类似js那样的函数回调去实现,感觉这样行的通
HttpUtil.instance.get("https://www.baidu.com",
//回调成功
onResponse: (responseStr){
print(responseStr);
},
//回调失败
onFailure: (errCode,errMsg){
print(errMsg);
},
);
下面直接贴实现的代码
- 函数的定义
/// 通过typedef给函数取个别名
typedef void OnResponse(String responseStr); //相当于Function(String responseStr);
typedef void OnFailure(int errCode,String errMsg);//相当于Function(int errCode,String errMsg);
- 回调接口的定义
///用抽象类实现接口
abstract class Callback{
void onResponse(String responseStr);
void onFailure(int errCode,String errMsg);
}
- HttpUtil.dart
/// Create [HttpUtil] by Lonsho in 2020-04-20.
/// @Description: TODO 网络请求库
/// @Version:1.0
import 'dart:convert' show utf8,jsonEncode;
import 'dart:io' show HttpClient,ContentType,HttpStatus;
class HttpUtil {
static HttpUtil _httpUtil;
static HttpClient _httpClient;
static HttpUtil get instance => _getInstance();
static HttpUtil getInstance() => _getInstance();
/// 使用工厂模式创建单例模式
factory HttpUtil() =>_getInstance();
HttpUtil._(){
///初始化
_httpClient = HttpClient();
}
static HttpUtil _getInstance(){
if(_httpUtil == null){
_httpUtil = HttpUtil._();
}
return _httpUtil;
}
/// get请求
/// [url] 请求链接
/// [paramsMap] 请求参数
/// [callback] 请求回调接口,如果设置了函数回调,此接口会失效
/// [onResponse] 请求成功函数回调
/// [onFailure] 请求失败函数回调
/// [contentType] 可选设置请求类型
/// [headers] 可选设置请求头
Future<String> get(String url,{ Callback callback,
OnResponse onResponse,
OnFailure onFailure,
String contentType,
Map<String,String> headers
}) async{
String result = "";
try{
var request = await _httpClient.getUrl(Uri.parse(url));
if(headers!=null){
headers.forEach((key,val){
request.headers.add(key, val);
});
}
request.headers.contentType = _initContentType(contentType);
var response = await request.close(); //获取网络请求响应
if(response.statusCode == HttpStatus.ok){ //http status 200
result = await response.transform(utf8.decoder).join();//响应内容
if(onResponse!=null)
onResponse(result);
else
callback?.onResponse(result);
}else{
result ="Error postting url: $url \nHttp status ${response.statusCode}";
if(onFailure!=null)
onFailure(response.statusCode,result);
else
callback?.onFailure(response.statusCode,result);
}
}catch(exception){
if(onFailure!=null)
onFailure(0,"error => $exception");
else
callback?.onFailure(0,"error => $exception");
result = "error => $exception";
}finally{
_httpClient.close();
}
return result;
}
/// post请求
/// [url] 请求链接
/// [paramsMap] 请求参数
/// [callback] 请求回调接口,如果设置了函数回调,此接口会失效
/// [onResponse] 请求成功函数回调
/// [onFailure] 请求失败函数回调
/// [contentType] 可选设置请求类型
/// [headers] 可选设置请求头
Future<String> post(String url,Map<String,dynamic> paramsMap,
{Callback callback,
OnResponse onResponse,
OnFailure onFailure,
String contentType,
Map<String,String> headers
}) async{
var params ="";
String result = "";
try{
//如果contentType为application/json,则需要将参数转为jsonString,否则无法正常请求
if(contentType!=null && contentType.toLowerCase().startsWith("application/json")){
params = jsonEncode(paramsMap);
}else{
//表单方式提交,拼接参数
if(paramsMap!=null){
paramsMap.forEach((key,val){
if(params!='') params +="&";
params+="$key=$val";
});
}
}
var request = await _httpClient.postUrl(Uri.parse(url));
if(headers!=null){ //设置headers
headers.forEach((name,value){
if(request.headers.value(name)==null) //如果 header不存在
request.headers.add(name, value); //添加header
else
request.headers.set(name, value); //修改header
});
}
request.headers.contentType = _initContentType(contentType);
request.write(params); //将参数提交到request上去
var response = await request.close(); //获取网络请求响应
if(response.statusCode == HttpStatus.ok){ //http status 200
result = await response.transform(utf8.decoder).join(); //响应内容
if(onResponse!=null)
onResponse(result); //请求成功函数回调
else
callback?.onResponse(result); //请求成功接口回调
return result;
} else {
result ="Error postting url: $url \nHttp status ${response.statusCode}";
if(onFailure!=null)
onFailure(response.statusCode,result);//请求失败函数回调
else
callback?.onFailure(response.statusCode,result);//请求失败接口回调
}
}catch(exception){
//抛出异常
if(onFailure!=null)
onFailure(0,"error => $exception");
else
callback?.onFailure(0,"error => $exception");
result = "error => $exception";
} finally{
_httpClient.close();
}
return result;
}
///获取请求头
ContentType _initContentType(String contentType){
if(contentType!=null && contentType.length!=0)
return ContentType.parse(contentType);
else
return ContentType("application","x-www-form-urlencoded");
}
}
使用方法
- 函数回调
void main() async{
HttpUtil.instance.get("https://www.baidu.com",
//成功
onResponse: (responseStr){
print(responseStr);
},
//失败
onFailure: (errCode,errMsg){
print(errMsg);
},
);
}
- 链式回调
void main() async{
HttpUtil.instance.get("https://www.baidu.com")
.then((res){
print(res);
});
}
- 接口回调
class NetTest implements Callback{
void main() async{
//内部实现接口
HttpUtil.instance.get("https://www.baidu.com",
//回调接口
callback:this,
);
//外部类实现接口
HttpUtil.instance.get("https://www.baidu.com",
//回调接口
callback:MyNetCallback(),
);
}
@override
void onFailure(int errCode, String errMsg) {
// TODO: implement onFailure
print(errMsg);
}
@override
void onResponse(String responseStr) {
// TODO: implement onResponse
print(responseStr);
}
}
class MyNetCallback implements Callback{
@override
void onFailure(int errCode, String errMsg) {
// TODO: implement onFailure
print(errMsg);
}
@override
void onResponse(String responseStr) {
// TODO: implement onResponse
print(responseStr);
}
}
- 同步请求
由于默认都是异步请求,如果需要用到同步请求,可以通过设置
await
关键字来阻塞线程实现同步
void main() async{
await HttpUtil.instance.get("https://www.baidu.com",
//成功
onResponse: (responseStr){
print(responseStr);
},
//失败
onFailure: (errCode,errMsg){
print(errMsg);
},
);
//直接赋值
String result = await HttpUtil.instance.get("https://www.baidu.com");
print(result);
}
如果有写得不好的地方,欢迎指正