1. Http dio 庫(3.2.2)
Flutter 里面提供了網(wǎng)絡(luò)請(qǐng)求的api 伦糯,不過直接使用起來會(huì)有點(diǎn)麻煩册舞,于是有了很多第三方的網(wǎng)絡(luò)庫盐捷,dio 就是其中之一,也是相對(duì)比較成熟的庫讶坯。那為什么選 dio 呢?
官方描述: dio是一個(gè)強(qiáng)大的Dart Http請(qǐng)求庫岗屏,支持Restful API辆琅、FormData、攔截器担汤、請(qǐng)求取消涎跨、Cookie管理、文件上傳/下載崭歧、超時(shí)隅很、自定義適配器等
而且使用簡(jiǎn)單,不過我們?cè)谑褂脮r(shí)候率碾,還是需要簡(jiǎn)單封裝叔营,便于以后切換庫。也讓代碼更加清晰易用所宰。
封裝的簡(jiǎn)單目錄結(jié)構(gòu):
一個(gè)HttpHelper 工具類绒尊,CommonInterceptor 攔截器,HttpIOException 異常封裝
2. 單例
通過dart 自帶的 factory 工廠模式仔粥,進(jìn)行單例設(shè)計(jì)婴谱。
調(diào)用是時(shí),直接 HttpUtil httpUtil = HttpUtil() 即可躯泰。
_httpInstance 以及 _init都是對(duì)外不可見谭羔。(dart 里面 _ 開頭為內(nèi)部方法、內(nèi)部變量)
class HttpUtil {
factory HttpUtil() => _httpInstance();
static HttpUtil _instance;
static HttpUtil _httpInstance() {
if (_instance == null) {
_instance = HttpUtil._init();
}
return _instance;
}
}
3. 基礎(chǔ)網(wǎng)絡(luò)屬性設(shè)置
dio 中基礎(chǔ)的網(wǎng)絡(luò)設(shè)置麦向,在BaseOptions 中進(jìn)行設(shè)置.
這里簡(jiǎn)單設(shè)置了 contentType瘟裸,連接超時(shí)時(shí)間,接收超時(shí)時(shí)間诵竭,以及host ( baseUrl 的設(shè)置 )话告。相對(duì)固定的一些基礎(chǔ)參數(shù)可以直接在新建的時(shí)候設(shè)置兼搏,一些動(dòng)態(tài)的數(shù)據(jù),可以通過攔截器的形式動(dòng)態(tài)添加或設(shè)置沙郭。
設(shè)置好的參數(shù)給 new Dio 進(jìn)行dio 創(chuàng)建佛呻。
HttpUtil._init() {
orgOption = BaseOptions(
contentType: CONTENT_TYPE,
connectTimeout: CONNECT_TIMEOUT,
receiveTimeout: RECEIVE_TIMEOUT,
baseUrl: HOST);
_dio = new Dio(orgOption);
}
BaseOptions的其他參數(shù):
4. 攔截器設(shè)置
使用過攔截器方知攔截器的重要性,攔截器多網(wǎng)絡(luò)上的處理至關(guān)重要棠绘,可以接解決很多疑難需求件相。
攔截器是順序調(diào)用,最先添加的先調(diào)用氧苍,后添加的后調(diào)用
dio 也提供了攔截器的設(shè)置夜矗。這里簡(jiǎn)單做一個(gè)封裝:
//攔截器添加
addInterceptor(Interceptor interceptor) {
if (null != _dio) {
_dio.interceptors.add(interceptor);
}
}
addInterceptors(List<Interceptor> interceptorList) {
if (null != _dio) {
_dio.interceptors.addAll(interceptorList);
}
}
新建攔截器
攔截器有三個(gè)方法可以實(shí)現(xiàn)攔截:、
1 . FutureOr<dynamic> onRequest(RequestOptions options) => options;
請(qǐng)求出去之前的處理
2 . FutureOr<dynamic> onResponse(Response response) => response;
請(qǐng)求結(jié)果回來的處理
3 . FutureOr<dynamic> onError(DioError err) => err;
請(qǐng)求發(fā)生異常時(shí)候的處理
這里新建兩個(gè)攔截器:
- 通用的請(qǐng)求頭
- 網(wǎng)絡(luò)錯(cuò)誤處理让虐,做統(tǒng)一信息出來
CommonInterceptor.dart:
///可以按需要添加攔截器紊撕,實(shí)現(xiàn)一些通用的功能,例如統(tǒng)一的請(qǐng)求頭赡突,統(tǒng)一的參數(shù)添加
///下面是例子
class CommonHeaderInterceptor extends Interceptor {
@override
FutureOr<dynamic> onRequest(RequestOptions options) {
options.headers.addAll({
"deviceId":"123444",
"requestId":"ddfsgg"
});
return super.onRequest(options);
}
}
class ErrorInterceptor extends Interceptor {
@override
FutureOr<dynamic> onError(DioError err) {
print(err.type);//也可以區(qū)分類型对扶,自定義message;
if(null != err.response) {
err.message = "網(wǎng)絡(luò)錯(cuò)誤請(qǐng)稍后重試(" + err.response.statusCode.toString() + ")";
} else if(null != err.request) {
err.message = "網(wǎng)絡(luò)異常,請(qǐng)檢查網(wǎng)絡(luò)情況";
}
return super.onError(err);
}
}
5. 異常封裝
dio 本來就封裝了 DioError 惭缰,不過相對(duì)來說浪南,DioError比較復(fù)雜,也不一定適合所有的需求漱受,故此络凿,做一個(gè)簡(jiǎn)單的封裝。在接收到 DioError 或者其他異常的時(shí)候昂羡,通過 Future.error 拋出絮记,自定義的異常,定義拋出信息虐先。
class HttpIOException implements Exception{
int code;
String message;
HttpIOException(this.code,this.message);
}
6. 調(diào)用
對(duì)外的調(diào)用比價(jià)簡(jiǎn)單怨愤,提供 get post 等api 外部調(diào)用, 返回 Future<dynamic> 蛹批,進(jìn)行函數(shù)式調(diào)用返回撰洗。
如何調(diào)用:
httpUtil.post("getServerTimestamp", getRequestData())
.then((resp) {
//這里可以做想要的轉(zhuǎn)換,也可以什么都不做
HomePageResp result = new HomePageResp.fromJson(resp);
return result;
});
最后直接來個(gè)完整的代碼
import 'package:dio/dio.dart';
import 'dart:io';
import 'dart:async';
import 'package:move_forever_app/core/http/HttpIOExcepiton.dart';
import 'dart:convert';
const String GET = "get";
const String POST = "post";
const String HOST = "https://your_host_url.com/";
const int CONNECT_TIMEOUT = 10000;
const int RECEIVE_TIMEOUT = 3000;
final ContentType CONTENT_TYPE = ContentType.json;
typedef ErrorCallback = void Function(int count, String msg);
class HttpUtil {
factory HttpUtil() => _httpInstance();
static HttpUtil _instance;
Dio _dio;
BaseOptions orgOption;
static HttpUtil _httpInstance() {
if (_instance == null) {
_instance = HttpUtil._init();
}
return _instance;
}
HttpUtil._init() {
orgOption = BaseOptions(
contentType: CONTENT_TYPE,
connectTimeout: CONNECT_TIMEOUT,
receiveTimeout: RECEIVE_TIMEOUT,
baseUrl: HOST);
_dio = new Dio(orgOption);
}
//攔截器添加
addInterceptor(Interceptor interceptor) {
if (null != _dio) {
_dio.interceptors.add(interceptor);
}
}
addInterceptors(List<Interceptor> interceptorList) {
if (null != _dio) {
_dio.interceptors.addAll(interceptorList);
}
}
//post
Future<dynamic> post (String path,postData) {
return request(path, POST, postData);
}
//get
Future<dynamic> get (String path) {
return request(path, GET, null);
}
Future<dynamic> request(String path, String mode, postData) async {
try {
switch (mode) {
case GET:
var getResponse = await _dio.get(path);
return new Future<dynamic>((){
return getResponse.data;
});
case POST:
//做一層json 轉(zhuǎn)換
var postResponse = await _dio.post<Map<String,dynamic>>(path, data: json.encode(postData));
return new Future<dynamic>((){
return postResponse.data;
});
}
} on DioError catch (exception) {
return new Future.error(new HttpIOException(exception.response.statusCode, exception.message));
} catch (error) {
return new Future.error(new HttpIOException(-2, error.toString()));
}
return new Future.error(new HttpIOException(-1, "not supported"));
}
}
7. 總結(jié)
封裝比較簡(jiǎn)單腐芍,這個(gè)也是dio本來就是一個(gè)比較完善的庫的原因差导。
但是里面還有很多可以擴(kuò)展的地方,攔截器可以按需要添加甸赃,異常封裝也可以按需進(jìn)行柿汛,get post 只是最基本的請(qǐng)求方式冗酿,還可以對(duì)其他進(jìn)行添加封裝埠对。