Сетевой запрос Flutter Пакет Dio

Flutter

   Существует два способа использования сетевых запросов в проекте Flutter: собственный класс сетевых запросов Dart HttpClient и сторонняя библиотека сетевых запросов с открытым исходным кодом. В сторонней библиотеке http-запросов, исходный код которой открыт сообществом Dart.Китайская сеть FlutterОткрытый исходный кодБиблиотека ДиоСамый популярный.
Ниже мы сравним эти два способа сетевых запросов, а затем посмотрим на запрос HttpManager, насколько просты в использовании пакеты библиотеки Dio с веб-инструментами.

Сравнение библиотеки сетевых запросов

класс HttpClient

Библиотека Dart IO предоставляет несколько классов для инициирования HTTP-запросов.Мы можем напрямую использовать HttpClient для инициирования запросов.

Использование HttpClient для инициирования запроса делится на пять шагов:

  1. Создайте HttpClient
 HttpClient httpClient = new HttpClient();
  1. Открыть Http-соединение, установить заголовок запроса
HttpClientRequest request = await httpClient.getUrl(uri);

На этом шаге можно использовать любой метод Http, например httpClient.post(...), httpClient.delete(...) и так далее. Если вы включаете параметр запроса, вы можете добавить его при создании uri, например:

Uri uri=Uri(scheme: "https", host: "flutterchina.club", queryParameters: {
    "xx":"xx",
    "yy":"dd"
  });

Вам может быть предоставлен заголовок запроса HttpClientRequest, например:

request.headers.add("user-agent", "test");

Если это сообщение или сообщение, которое может содержать метод тела запроса, вы можете отправить тело запроса через объект HttpClientRequest, например:

String payload="...";
request.add(utf8.encode(payload)); 
//request.addStream(_inputStream); //可以直接添加输入流
  1. ожидание подключения к серверу
HttpClientResponse response = await request.close();

После завершения этого шага информация о запросе отправляется на сервер, и возвращается объект HttpClientResponse, который содержит заголовок ответа (заголовок) и поток ответа (поток тела ответа), а затем содержимое ответа может быть можно получить, прочитав поток ответов.

  1. прочитать содержимое ответа
String responseBody = await response.transform(utf8.decoder).join();

Данные, возвращаемые сервером, мы получаем, читая поток ответа, мы можем задать формат кодировки при чтении, здесь utf8.

  1. Запрос окончен, закройте httpclient
httpClient.close();

После закрытия клиента все запросы, сделанные через этот клиент, прерываются.

Вышеуказанные шаги показывают, как используется собственная сеть dart HttpClient. Можно обнаружить, что напрямую использовать HttpClient для инициирования сетевых запросов более проблематично. Многие вещи необходимо обрабатывать вручную. Если это связано с загрузкой / выгрузкой файлов, управлением файлами cookie и т. Д. ., станет очень громоздким.Да и сам HttpClient имеет слабые функции, и многие общие функции не поддерживаются.

Библиотека Дио

dio — это мощная библиотека запросов Dart Http, которая поддерживает Restful API, FormData, перехватчики, отмену запросов, управление файлами cookie, загрузку/выгрузку файлов, тайм-аут и т. д.

  1. pubspec.yaml добавить зависимости
dependencies:
  dio: ^x.x.x #请使用pub上的最新版本
  1. Импорт ссылок и создание экземпляров dio
import 'package:dio/dio.dart';
Dio dio =  Dio();

Затем вы можете инициировать сетевые запросы через экземпляр dio.Обратите внимание, что экземпляр dio может инициировать несколько HTTP-запросов.Вообще говоря, когда приложение имеет только один источник данных http, dio должен использовать одноэлементный режим.

  1. инициировать сетевой запрос

Получить запрос

Response response;
response=await dio.get("/test?id=12&name=cheney")
print(response.data.toString());

Отправить запрос

Response response;
response=await dio.post("/test",data:{"id":12,"name":"cheney"})
print(response.data.toString());

Выше приведено основное использование сетевых запросов библиотеки Dio. Это очень просто? Помимо этих основных применений, dio также поддерживает конфигурацию запросов, перехватчики и т. д. Официальная информация более подробная, поэтому я не буду повторять их здесь. подробности см. на домашней странице dio:GitHub.com/флаттер доение….

Инкапсулировать класс инструментов Dio

Зачем инкапсулировать дио

Сделайте некоторую общедоступную обработку, чтобы облегчить гибкое использование.

сделать эти пакеты

  • Унифицированная обработка префиксов запросов; (www.xx.com/api/v1без префикса каждого запроса)
  • Унифицированный вывод информации запроса или ответа;
  • Унифицированная обработка сообщений об ошибках;
  • Совместимость с различными сетевыми запросами, поддержка загрузки и скачивания файлов;
  • Поддерживает две формы синхронного обратного вызова и асинхронного будущего.
  • Возвращаемые данные автоматически преобразуются в формат json и по умолчанию анализируют общедоступную модель данных;

содержание

имя класса описывать
HttpManager Класс управления сетевыми запросами
HttpError Единый класс ошибок сетевого запроса
LogInterceptor инструмент сетевых запросов

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请求成功回调
typedef HttpSuccessCallback<T> = void Function(dynamic data);

///失败回调
typedef HttpFailureCallback = void Function(HttpError data);

///数据解析回调
typedef T JsonParse<T>(dynamic data);


/// @desc  封装 http 请求
/// @time 2019/3/15 10:35 AM
/// @author Cheney
class HttpManager {
    init                        : 初始化baseUrl,超时时间等
    get                         : get请求同步回调
    post                        : post请求同步回调
    upload                      : 文件上传同步回调
    download                    : 文件下载同步回调
    getAsync                    : get 请求异步方式
    postAsync                   : post 请求异步方式
    uploadAsync                 : 文件上传异步方式
    downloadAsync               : 文件下载异步方式
    [...]
 }

Смотрите в конце подробный исходный код.

Здесь обрабатываются оценка сетевого подключения, отмена сетевых запросов, анализ формата данных по умолчанию и т. д. Формат анализируемых данных по умолчанию:

{
	"data":{},
	"statusCode":"0",
	"statusDesc":"02032008:用户授信未通过",
	"timestamp":1569206576392
}

Вы можете изменить его на свой собственный формат данных в соответствии с вашими потребностями.

HttpError

import 'package:dio/dio.dart';

/// @desc  网络请求错误
/// @time 2019/3/20 10:02 AM
/// @author Cheney
class HttpError {
  ///HTTP 状态码
  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;

  ///未知错误
  static const String UNKNOWN = "UNKNOWN";

  ///解析错误
  static const String PARSE_ERROR = "PARSE_ERROR";

  ///网络错误
  static const String NETWORK_ERROR = "NETWORK_ERROR";

  ///协议错误
  static const String HTTP_ERROR = "HTTP_ERROR";

  ///证书错误
  static const String SSL_ERROR = "SSL_ERROR";

  ///连接超时
  static const String CONNECT_TIMEOUT = "CONNECT_TIMEOUT";

  ///响应超时
  static const String RECEIVE_TIMEOUT = "RECEIVE_TIMEOUT";

  ///发送超时
  static const String SEND_TIMEOUT = "SEND_TIMEOUT";

  ///网络请求取消
  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 = "网络连接超时,请检查网络设置";
        break;
      case DioErrorType.RECEIVE_TIMEOUT:
        code = RECEIVE_TIMEOUT;
        message = "服务器异常,请稍后重试!";
        break;
      case DioErrorType.SEND_TIMEOUT:
        code = SEND_TIMEOUT;
        message = "网络连接超时,请检查网络设置";
        break;
      case DioErrorType.RESPONSE:
        code = HTTP_ERROR;
        message = "服务器异常,请稍后重试!";
        break;
      case DioErrorType.CANCEL:
        code = CANCEL;
        message = "请求已被取消,请重新请求";
        break;
      case DioErrorType.DEFAULT:
        code = UNKNOWN;
        message = "网络异常,请稍后重试!";
        break;
    }
  }

  @override
  String toString() {
    return 'HttpError{code: $code, message: $message}';
  }
}

Здесь задаются различные описания ошибок, и вы можете изменить их в соответствии с вашими потребностями.

LogInterceptor

import 'package:dio/dio.dart';
import 'package:flutter_common_utils/log_util.dart';

void log2Console(Object object) {
  LogUtil.v(object);
}

/// @desc  自定义日志拦截器
///@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,
  });

  [...]
}

Смотрите в конце подробный исходный код.

Здесь LogUtl используется по умолчанию для вывода журналов.Вы можете изменить свой собственный класс инструмента вывода журнала в соответствии с вашими потребностями.

Пример использования

Шаг 1: Инициализировать

//初始化 Http,
  HttpManager().init(
    baseUrl: Api.getBaseUrl(),
    interceptors: [
      HeaderInterceptor(),
      LogInterceptor(),
    ],
  );

Шаг 2: Создайте сетевой запрос

///同步回调模式
///get 网络请求
void _get(){
   HttpManager().get(
      url: "/app/info",
      params: {"iouCode": iouCode},
      successCallback: (data) {
        
      },
      errorCallback: (HttpError error) {
       
      },
      tag: "tag",
    );
}
///post 网络请求
void _post(){
     HttpManager().post(
      url: "/app/info",
      data: {"iouCode": iouCode},
      successCallback: (data) {
        
      },
      errorCallback: (HttpError error) {
        
      },
      tag: "tag",
    );
}

///下载文件
void _download(){
     HttpManager().download(
      url: "/app/download",
      savePath: "/savePath",
      onReceiveProgress: (int count, int total) {
      },
      successCallback: (data) {
        
      },
      errorCallback: (HttpError error) {
        
      },
      tag: tag,
    );
}

///上传文件
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) {
          
        },
      );
}


///异步模式
///get 请求
void _getAysnc() async{
     String timestamp =
        await HttpManager().getAsync(url: "/app/info", tag: "syncTime");
}

///post 请求
void _postAysnc() async{
   await HttpManager().postAsync(
        url: "app/info",
        tag: "tag",
        data: {
          'bannerTypes': ["wealthBanner"],
        },
        jsonParse: (json) => Pager(json, (data) => ImageAd(data)))
}

///下载文件
void _downloadAsync() async{
    await HttpManager().downloadAsync(
      url: "/app/download",
      savePath: "/savePath",
      onReceiveProgress: (int count, int total) {
      },
      tag: "tag",
    );
}

///上传文件
void _uploadAsync() async{
FormData data = FormData.fromMap({
        "file": await MultipartFile.fromFile(path, filename: "$photoTime"),
      });
  await  HttpManager().uploadAsync(
        url: "/app/upload",
        data: data,
        tag: "tag",
       
      );
}

наконец

  Если у вас возникнут проблемы во время использования, оставьте сообщение ниже, чтобы сообщить об этом.

  Адрес библиотеки инструментов

учебные материалы

Пожалуйста, поднимите палец вверх! Потому что ваши лайки - моя самая большая поддержка, спасибо!