flutter dio network request encapsulation implementation

flutter dio network request encapsulation implementation

Article Links:   https://juejin.im/post/6844904098643312648

There are two ways to use network requests in the Flutter project, which are Dart's native network request HttpClient class and third-party open source network request libraries. In the third-party http request library open sourced by the Dart community Flutter Chinese Network open source Dio library The most popular.
   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:

  1. Create an HttpClient
 HttpClient httpClient = new HttpClient();
copy code
  1. 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
  1. 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.

  1. 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.

  1. 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...

  1. pubspec.yaml add dependencies

dependencies: dio: ^x.x.x #Please use the latest version on pub

  1. 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.

  1. 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.

  Tool library address

Article Links:   https://juejin.im/post/6844904098643312648

 

 

Tags: Flutter

Posted by wigz01 on Tue, 17 May 2022 10:00:04 +0300