flutter dio network request encapsulation implementation
Article Links: https://juejin.im/post/6844904098643312648
Let's first compare these two network request methods, and then look at how to encapsulate the convenient network request tool class HttpManager based on the Dio library.
Network request library comparison
HttClient class
The Dart IO library provides some classes for initiating Http requests. We can directly use HttpClient to initiate requests.
Using HttpClient to initiate a request is divided into five steps:
- Create an HttpClient
HttpClient httpClient = new HttpClient(); copy code
- Open Http connection, set request header
HttpClientRequest request = await httpClient.getUrl(uri); copy code
This step can use any Http Method, such as httpClient.post(...), httpClient.delete(...) and so on. If you include a Query parameter, you can add it when building the uri, such as:
Uri uri=Uri(scheme: "https", host: "flutterchina.club", queryParameters: { "xx":"xx", "yy":"dd" }); copy code
The request header can be set through HttpClientRequest, such as:
request.headers.add("user-agent", "test"); copy code
If it is a post or put that can carry a request body method, you can send the request body through the HttpClientRequest object, such as:
String payload="..."; request.add(utf8.encode(payload)); //request.addStream(_inputStream); //You can add input stream directly copy code
- waiting to connect to the server
HttpClientResponse response = await request.close(); copy code
After this step is completed, the request information has been sent to the server, and an HttpClientResponse object is returned, which contains the response header (header) and the response stream (the Stream of the response body), and then the response content can be obtained by reading the response stream.
- read response content
String responseBody = await response.transform(utf8.decoder).join(); copy code
We get the data returned by the server by reading the response stream, we can set the encoding format when reading, here is utf8.
- The request is over, close the HttpClient
httpClient.close(); copy code
After closing a client, all requests made through that client are aborted.
The above steps are the use of dart's native network HttpClient. It can be found that it is more troublesome to use HttpClient to initiate network requests directly. Many things have to be handled manually. If it involves file upload/download, Cookie management, etc., it will become very cumbersome. And HttpClient itself has weak functions, and many common functions are not supported.
Dio library
dio is a powerful Dart Http request library that supports Restful API, FormData, interceptors, request cancellation, Cookie management, file upload/download, timeout, etc...
- pubspec.yaml add dependencies
dependencies: dio: ^x.x.x #Please use the latest version on pub
- Import references and create dio instances
import 'package:dio/dio.dart';
Dio dio = Dio();
Next, you can initiate network requests through a dio instance. Note that a dio instance can initiate multiple http requests. Generally speaking, when the APP has only one http data source, dio should use the singleton mode.
- initiate a network request
Get request
Response response;
response=await dio.get("/test?id=12&name=cheney")
print(response.data.toString());
Post request
Response response;
response=await dio.post("/test",data:{"id":12,"name":"cheney"})
print(response.data.toString());
The above is the basic use of Dio library network requests. Is it very simple? In addition to these basic usages, dio also supports request configuration, interceptors, etc. The official information is more detailed, so I will not repeat them here. For details, please refer to the dio homepage: github.com/flutterchin... .
Encapsulate Dio tool class
Why encapsulate dio
Do some public processing to facilitate flexible use.
do those packages
- Unified processing of request prefixes; ( www.xx.com/api/v1 without prefixing every request)
- Unified output of request or response information;
- Unified error message handling;
- Compatible with a variety of network requests, support file upload and download;
- Supports two forms of synchronous callback and asynchronous Future
- The returned data is automatically converted to json format and parses the public data model by default;
content
class name | describe |
---|---|
HttpManager | Network request management class |
HttpError | Network request unified error class |
LogInterceptor | network request tool |
HttpManager
import 'dart:core'; import 'package:connectivity/connectivity.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_common_utils/http/http_error.dart'; import 'package:flutter_common_utils/log_util.dart'; ///http request success callback typedef HttpSuccessCallback<T> = void Function(dynamic data); ///fail callback typedef HttpFailureCallback = void Function(HttpError data); ///Data parsing callback typedef T JsonParse<T>(dynamic data); /// @desc wraps http requests /// @time 2019/3/15 10:35 AM /// @author Cheney class HttpManager { init : initialization baseUrl,timeout, etc. get : get request synchronization callback post : post request synchronization callback upload : File upload synchronization callback download : File download synchronization callback getAsync : get request asynchronously postAsync : post request asynchronously uploadAsync : Asynchronous file upload downloadAsync : File download asynchronously [...] }
See the end for the detailed source code.
This handles network connection judgment, cancellation of network requests, default data format parsing, etc. Default parsed data format:
{
"data":{},
"statusCode":"0",
"statusDesc":"02032008:User credit failed",
"timestamp":1569206576392
}
You can change it to your own data format according to your needs
HttpError
import 'package:dio/dio.dart';
/// @desc network request error
/// @time 2019/3/20 10:02 AM
/// @author Cheney
class HttpError {
///HTTP status code
static const int UNAUTHORIZED = 401;
static const int FORBIDDEN = 403;
static const int NOT_FOUND = 404;
static const int REQUEST_TIMEOUT = 408;
static const int INTERNAL_SERVER_ERROR = 500;
static const int BAD_GATEWAY = 502;
static const int SERVICE_UNAVAILABLE = 503;
static const int GATEWAY_TIMEOUT = 504;
///unknown mistake
static const String UNKNOWN = "UNKNOWN";
///parse error
static const String PARSE_ERROR = "PARSE_ERROR";
///Network Error
static const String NETWORK_ERROR = "NETWORK_ERROR";
///protocol error
static const String HTTP_ERROR = "HTTP_ERROR";
///certificate error
static const String SSL_ERROR = "SSL_ERROR";
///Connection timed out
static const String CONNECT_TIMEOUT = "CONNECT_TIMEOUT";
///response timeout
static const String RECEIVE_TIMEOUT = "RECEIVE_TIMEOUT";
///send timeout
static const String SEND_TIMEOUT = "SEND_TIMEOUT";
///Network request cancel
static const String CANCEL = "CANCEL";
String code;
String message;
HttpError(this.code, this.message);
HttpError.dioError(DioError error) {
message = error.message;
switch (error.type) {
case DioErrorType.CONNECT_TIMEOUT:
code = CONNECT_TIMEOUT;
message = "The network connection timed out, please check the network settings";
break;
case DioErrorType.RECEIVE_TIMEOUT:
code = RECEIVE_TIMEOUT;
message = "Server exception, please try again later!";
break;
case DioErrorType.SEND_TIMEOUT:
code = SEND_TIMEOUT;
message = "The network connection timed out, please check the network settings";
break;
case DioErrorType.RESPONSE:
code = HTTP_ERROR;
message = "Server exception, please try again later!";
break;
case DioErrorType.CANCEL:
code = CANCEL;
message = "The request has been cancelled, please request again";
break;
case DioErrorType.DEFAULT:
code = UNKNOWN;
message = "The network is abnormal, please try again later!";
break;
}
}
@override
String toString() {
return 'HttpError{code: $code, message: $message}';
}
}
A variety of error descriptions are set here, and you can modify them according to your needs.
LogInterceptor
import 'package:dio/dio.dart';
import 'package:flutter_common_utils/log_util.dart';
void log2Console(Object object) {
LogUtil.v(object);
}
/// @desc custom log interceptor
///@time 2019/3/18 9:15 AM
/// @author Cheney
class LogInterceptor extends Interceptor {
LogInterceptor({
this.request = true,
this.requestHeader = true,
this.requestBody = false,
this.responseHeader = true,
this.responseBody = false,
this.error = true,
this.logPrint = log2Console,
});
[...]
}
See the end for the detailed source code.
Here, LogUtl is used by default to output the log, and you can replace it with your own log output tool class according to your needs.
Step1: Initialize
//Initialize Http,
HttpManager().init(
baseUrl: Api.getBaseUrl(),
interceptors: [
HeaderInterceptor(),
LogInterceptor(),
],
);
Step2: Create a network request
///sync callback mode
///get network request
void _get(){
HttpManager().get(
url: "/app/info",
params: {"iouCode": iouCode},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: "tag",
);
}
///post network request
void _post(){
HttpManager().post(
url: "/app/info",
data: {"iouCode": iouCode},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: "tag",
);
}
///download file
void _download(){
HttpManager().download(
url: "/app/download",
savePath: "/savePath",
onReceiveProgress: (int count, int total) {
},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: tag,
);
}
///upload files
void _upload() async{
FormData data = FormData.fromMap({
"file": await MultipartFile.fromFile(path, filename: "$photoTime"),
});
HttpManager().upload(
url: "/app/upload",
data: data,
tag: "tag",
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
);
}
///async mode
///get request
void _getAysnc() async{
String timestamp =
await HttpManager().getAsync(url: "/app/info", tag: "syncTime");
}
///post request
void _postAysnc() async{
await HttpManager().postAsync(
url: "app/info",
tag: "tag",
data: {
'bannerTypes': ["wealthBanner"],
},
jsonParse: (json) => Pager(json, (data) => ImageAd(data)))
}
///download file
void _downloadAsync() async{
await HttpManager().downloadAsync(
url: "/app/download",
savePath: "/savePath",
onReceiveProgress: (int count, int total) {
},
tag: "tag",
);
}
///upload files
void _uploadAsync() async{
FormData data = FormData.fromMap({
"file": await MultipartFile.fromFile(path, filename: "$photoTime"),
});
await HttpManager().uploadAsync(
url: "/app/upload",
data: data,
tag: "tag",
);
}
At last
If you encounter problems during use, please leave a message below to communicate.
Article Links: https://juejin.im/post/6844904098643312648