dio
打開終端機,在專案目錄下,輸入以下內容。
flutter_base % flutter pub add dio
確認有dio版本。

語法
Dio().get(網址).then((res) {
成功
}).catchError((error) {
失敗
});
重新run。
1
2
3
4
5
6
7
8
9
10
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
void main() {
Dio().get('https://www.httpbin.org/get').then((res) {
print(res.data); // ""
}).catchError((error) {
print(error);
});
}
This app is linked to the debug service: ws://127.0.0.1:49201/iD0_5D0mbiE=/ws
Debug service listening on ws://127.0.0.1:49201/iD0_5D0mbiE=/ws
Connecting to VM Service at ws://127.0.0.1:49201/iD0_5D0mbiE=/ws
{args: {}, headers: {Accept: */*, Accept-Encoding: gzip, deflate, br, zstd, Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7, Host: www.httpbin.org, Origin: http://localhost:65521, Priority: u=1, i, Referer: http://localhost:65521/, Sec-Ch-Ua: "Chromium";v="146", "Not-A.Brand";v="24", "Google Chrome";v="146", Sec-Ch-Ua-Mobile: ?0, Sec-Ch-Ua-Platform: "macOS", Sec-Fetch-Dest: empty, Sec-Fetch-Mode: cors, Sec-Fetch-Site: cross-site, User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36, X-Amzn-Trace-Id: Root=1-69d89760-0e88bc5a1d8c9f993cf902c8}, origin: 42.73.190.130, url: https://www.httpbin.org/get}
Dio 封裝
1
2
3
4
5
6
7
8
9
class DioUtils {
final Dio _dio = Dio();
DioUtils(){
_dio.options.baseUrl = 'https://www.httpbin.org';
_dio.options.connectTimeout = Duration(seconds: 10); // 連線超出時間
_dio.options.sendTimeout = Duration(seconds: 10); // 傳送超出時間
_dio.options.receiveTimeout = Duration(seconds: 10); // 接收超出時間
}
}
使用.. 鏈式呼叫
鏈式呼叫(chaining call),可以在一個執行語句上,呼叫多次方法或指派多次屬性。
1
2
3
4
5
6
7
8
9
10
class DioUtils {
final Dio _dio = Dio();
DioUtils() {
_dio.options
..baseUrl = 'https://www.httpbin.org'
..connectTimeout = Duration(seconds: 10)
..sendTimeout = Duration(seconds: 10)
..receiveTimeout = Duration(seconds: 10);
}
}
增加攔截器
Interceptors是抽象類別,無法建立物件,要由子類別InterceptorsWrapper,才能建立物件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void _addInterceptors() {
_dio.interceptors.add(InterceptorsWrapper(
// 請求
onRequest: (context, handler) {
return handler.next(context);
},
// 伺服器回應
onResponse: (context, handler) {
// statusCode 介於200 ~ 299
if (context.statusCode! >= 200 && context.statusCode! < 300) {
return handler.next(context);
}
// statusCode 不是介於200 ~ 299 丟出Exception
handler.reject(DioException(requestOptions: context.requestOptions));
},
// 處理Exception
onError: (error, handler) {
// 丟出Exception
return handler.reject(error);
},
));
}
處理get 請求
傳回值類型是Future。
1
2
3
4
Future<Response<dynamic>> get(String url,
{Map<String, dynamic>? queryParameters}) async {
return _dio.get(url, queryParameters: queryParameters);
}
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class DioUtils {
final Dio _dio = Dio();
DioUtils() {
_dio.options
..baseUrl = 'https://www.httpbin.org'
..connectTimeout = Duration(seconds: 10)
..sendTimeout = Duration(seconds: 10)
..receiveTimeout = Duration(seconds: 10);
}
void _addInterceptors() {
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (context, handler) {
return handler.next(context);
},
onResponse: (context, handler) {
if (context.statusCode! >= 200 && context.statusCode! < 300) {
return handler.next(context);
}
handler.reject(DioException(requestOptions: context.requestOptions));
},
onError: (error, handler) {
return handler.reject(error);
},
));
}
Future<Response<dynamic>> get(String url,
{Map<String, dynamic>? queryParameters}) async {
return _dio.get(url, queryParameters: queryParameters);
}
}
Dio 與 async、Future
async 接收傳回值語法:
傳回值類型 函式名() async {
類型 result = await Future(
() {
return 傳回值;
},
);
等待上一步執行成功後會輸出result
}
Dio get()方法傳回值類型是Future。
1
2
3
4
5
void test() async {
DioUtils dioUtils = DioUtils();
Response<dynamic> response = await dioUtils.get('/get', queryParameters: {'name': 'cici'});
print(response);
}
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void main() {
test();
}
void test() async {
DioUtils dioUtils = DioUtils();
Response<dynamic> response = await dioUtils.get('/get', queryParameters: {'name': 'cici'});
print(response);
}
class DioUtils {
final Dio _dio = Dio();
DioUtils() {
_dio.options
..baseUrl = 'https://www.httpbin.org'
..connectTimeout = Duration(seconds: 10)
..sendTimeout = Duration(seconds: 10)
..receiveTimeout = Duration(seconds: 10);
}
void _addInterceptors() {
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (context, handler) {
return handler.next(context);
},
onResponse: (context, handler) {
if (context.statusCode! >= 200 && context.statusCode! < 300) {
return handler.next(context);
}
handler.reject(DioException(requestOptions: context.requestOptions));
},
onError: (error, handler) {
return handler.reject(error);
},
));
}
Future<Response<dynamic>> get(String url,
{Map<String, dynamic>? queryParameters}) async {
return _dio.get(url, queryParameters: queryParameters);
}
}
{"args":{"name":"cici"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate, br, zstd","Accept-Language":"zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7","Host":"www.httpbin.org","Origin":"http://localhost:49906","Priority":"u=1, i","Referer":"http://localhost:49906/","Sec-Ch-Ua":"\"Google Chrome\";v=\"147\", \"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"147\"","Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"macOS\"","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"cross-site","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36","X-Amzn-Trace-Id":"Root=1-69dc7ff2-515f14f57c4ff2de0b0047a5"},"origin":"42.73.190.130","url":"https://www.httpbin.org/get?name=cici"}
Response 泛型
Response的data成員變數為dynamic 類型
Response<dynamic> response = await dioUtils.get('/get');
Response 原始檔
1
2
3
class Response<T> {
// T類型根據使用者自訂,若T為dynamic,data就是dynamic類型
T? data;
Response 成員變數
1
2
3
4
response.data // 真正的資料(最重要)
response.statusCode // 狀態碼(200、404)
response.headers // 標頭
response.requestOptions // 請求資訊
Response.data 取出資料
前面提過,data都是dynamic類型,如果要使用,必須轉型。
dynamic是父類別,若要把父類別dynamic轉成子類別 Map<String, dynamic>,要使用as。
將response.data轉成Map類型。
Map<String, dynamic> res = response.data as Map<String, dynamic>;
轉成Map類型後,才可以使用Map方括號[key]取出資料
res["args"];
1
2
3
4
5
6
7
void test() async {
DioUtils dioUtils = DioUtils();
Response<dynamic> response =
await dioUtils.get('/get', queryParameters: {'name': 'cici'});
Map<String, dynamic> res = response.data as Map<String, dynamic>;
print(res["args"]);
}
{name: cici}
cast 轉型
假設今天的response.data的資料如下。
{data: {channels: [{id: 0, name: 推荐}, {id: 1, name: html}, {id: 2, name: 开发者资讯}, {id: 4, name: c++}, {id: 6, name: css}, {id: 7, name: 数据库}, {id: 8, name: 区块链}, {id: 9, name: go}, {id: 10, name: 产品}, {id: 11, name: 后端}, {id: 12, name: linux}, {id: 13, name: 人工智能}, {id: 14, name: php}, {id: 15, name: javascript}, {id: 16, name: 架构}, {id: 17, name: 前端}, {id: 18, name: python}, {id: 19, name: java}, {id: 20, name: 算法}, {id: 21, name: 面试}, {id: 22, name: 科技动态}, {id: 23, name: js}, {id: 24, name: 设计}, {id: 25, name: 数码产品}, {id: 26, name: 软件测试}]},
message: OK}
response.data是Map資料結構,有二個key,分別是:
data
message
response.data[“data”]裡面是Map資料結構,有一個key是channels。
1
2
3
4
5
6
void test() async {
DioUtils dioUtils = DioUtils();
Response<dynamic> response = await dioUtils.get('channels');
Map<String, dynamic> res = response.data as Map<String, dynamic>;
print(res["data"]);
}
{channels: [{id: 0, name: 推荐}, {id: 1, name: html}, {id: 2, name: 开发者资讯}, {id: 4, name: c++}, {id: 6, name: css}, {id: 7, name: 数据库}, {id: 8, name: 区块链}, {id: 9, name: go}, {id: 10, name: 产品}, {id: 11, name: 后端}, {id: 12, name: linux}, {id: 13, name: 人工智能}, {id: 14, name: php}, {id: 15, name: javascript}, {id: 16, name: 架构}, {id: 17, name: 前端}, {id: 18, name: python}, {id: 19, name: java}, {id: 20, name: 算法}, {id: 21, name: 面试}, {id: 22, name: 科技动态}, {id: 23, name: js}, {id: 24, name: 设计}, {id: 25, name: 数码产品}, {id: 26, name: 软件测试}]}
而response.data[“data”][“channels”]裡面的資料則是list
1
2
3
4
DioUtils dioUtils = DioUtils();
Response<dynamic> response = await dioUtils.get('channels');
Map<String, dynamic> res = response.data as Map<String, dynamic>;
print(res["data"]["channels"]);
[{id: 0, name: 推荐}, {id: 1, name: html}, {id: 2, name: 开发者资讯}, {id: 4, name: c++}, {id: 6, name: css}, {id: 7, name: 数据库}, {id: 8, name: 区块链}, {id: 9, name: go}, {id: 10, name: 产品}, {id: 11, name: 后端}, {id: 12, name: linux}, {id: 13, name: 人工智能}, {id: 14, name: php}, {id: 15, name: javascript}, {id: 16, name: 架构}, {id: 17, name: 前端}, {id: 18, name: python}, {id: 19, name: java}, {id: 20, name: 算法}, {id: 21, name: 面试}, {id: 22, name: 科技动态}, {id: 23, name: js}, {id: 24, name: 设计}, {id: 25, name: 数码产品}, {id: 26, name: 软件测试}]
把response.data[“data”][“channels”] 轉型成 List
1
2
3
4
5
6
7
void test() async {
DioUtils dioUtils = DioUtils();
Response<dynamic> response = await dioUtils.get('channels');
Map<String, dynamic> res = response.data as Map<String, dynamic>;
// 轉型成List
List list = res["data"]["channels"] as List<dynamic> ;
}
而每個元素的資料結構是Map<String, dynamic>,下方key為id,value的類型為int,key為name,value的類型為String。
{id: 0, name: 推荐}
把List中每個元素轉型成Map<String, dynamic>,因為是轉型list中的每個元素,使用cast。
1
2
3
4
5
6
7
8
9
void test() async {
DioUtils dioUtils = DioUtils();
Response<dynamic> response = await dioUtils.get('channels');
Map<String, dynamic> res = response.data as Map<String, dynamic>;
// 轉成list 但裡面的元素仍為dynamic
List list = res["data"]["channels"] as List<dynamic>;
// 裡面的元素轉成Map<String, dynamic> 類型
List<Map<String, dynamic>> _list = list.cast<Map<String, dynamic>>();
}
List<dynamic> 不能直接變成 List<Map<String,dynamic>>,必須用cast。
其它替代寫法:把每一個元素dynamic轉成Map<String, dynamic>
1
2
3
_list = (res["data"]["channels"] as List)
.map((e) => e as Map<String, dynamic>)
.toList();
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
void main() {
test();
}
void test() async {
DioUtils dioUtils = DioUtils();
Response<dynamic> response = await dioUtils.get('channels');
Map<String, dynamic> res = response.data as Map<String, dynamic>;
// 轉成list 但裡面的元素仍為dynamic
List list = res["data"]["channels"] as List<dynamic>;
// 轉成list,裡面的元素也轉成Map<String, dynamic> 類型
List<Map<String, dynamic>> _list = list.cast<Map<String, dynamic>>();
}
class DioUtils {
final Dio _dio = Dio();
DioUtils() {
_dio.options
..baseUrl = 'https://geek.itheima.net/v1_0/'
//..baseUrl = 'https://www.httpbin.org'
..connectTimeout = Duration(seconds: 10)
..sendTimeout = Duration(seconds: 10)
..receiveTimeout = Duration(seconds: 10);
}
void _addInterceptors() {
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (context, handler) {
return handler.next(context);
},
onResponse: (context, handler) {
if (context.statusCode! >= 200 && context.statusCode! < 300) {
return handler.next(context);
}
handler.reject(DioException(requestOptions: context.requestOptions));
},
onError: (error, handler) {
return handler.reject(error);
},
));
}
Future<Response<dynamic>> get(String url,
{Map<String, dynamic>? queryParameters}) async {
return _dio.get(url, queryParameters: queryParameters);
}
}