dio: ^4.0.0
http: ^0.13.3
dio_cookie_manager: ^2.0.0
cookie_jar: ^3.0.1
dio_http2_adapter: ^2.0.0
shared_preferences: ^2.0.7

dio_util.dart

//使用单例模式进行Dio封装

//因为我们的应用程序在每个页面中都会用到网络请求,
//那么如果我们每次请求的时候都去实例化一个Dio,
//无非是增加了系统不必要的开销,
//而使用单例模式对象一旦创建每次访问都是同一个对象,
//不需要再次实例化该类的对象。 import 'dart:io'; import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:tomato/page/dio/dio_cache_interceptors.dart';
import 'package:tomato/page/dio/dio_interceptors.dart';
import 'package:tomato/page/dio/dio_method.dart';
import 'package:tomato/page/dio/dio_token_interceptors.dart';
import 'package:tomato/page/dio/dio_transformer.dart'; class DioUtil {
/// 连接超时时间
static const int CONNECT_TIMEOUT = 6 * 1000; /// 响应超时时间
static const int RECEIVE_TIMEOUT = 6 * 1000; /// 请求的URL前缀
static String BASE_URL = "http://39.108.223.110:9199"; /// 是否开启网络缓存,默认false
static bool CACHE_ENABLE = false; /// 最大缓存时间(按秒), 默认缓存七天,可自行调节
static int MAX_CACHE_AGE = 7 * 24 * 60 * 60; /// 最大缓存条数(默认一百条)
static int MAX_CACHE_COUNT = 100; static DioUtil? _instance;
static Dio _dio = Dio();
Dio get dio => _dio; DioUtil._internal() {
_instance = this;
_instance!._init();
} factory DioUtil() => _instance ?? DioUtil._internal(); static DioUtil? getInstance() {
_instance ?? DioUtil._internal();
return _instance;
} /// 取消请求token
CancelToken _cancelToken = CancelToken(); /// cookie
CookieJar cookieJar = CookieJar(); _init() {
/// 初始化基本选项
BaseOptions options = BaseOptions(
baseUrl: BASE_URL,
connectTimeout: CONNECT_TIMEOUT,
receiveTimeout: RECEIVE_TIMEOUT); /// 初始化dio
_dio = Dio(options); /// 添加拦截器
_dio.interceptors.add(DioInterceptors()); /// 添加转换器
_dio.transformer = DioTransformer(); /// 添加cookie管理器
_dio.interceptors.add(CookieManager(cookieJar)); /// 刷新token拦截器(lock/unlock)
// _dio.interceptors.add(DioTokenInterceptors()); /// 添加缓存拦截器
_dio.interceptors.add(DioCacheInterceptors());
} /// 设置Http代理(设置即开启)
void setProxy({String? proxyAddress, bool enable = false}) {
if (enable) {
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(HttpClient client) {
client.findProxy = (uri) {
return proxyAddress ?? "";
};
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
};
}
} /// 设置https证书校验
void setHttpsCertificateVerification({String? pem, bool enable = false}) {
if (enable) {
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
client.badCertificateCallback =
(X509Certificate cert, String host, int port) {
if (cert.pem == pem) {
// 验证证书
return true;
}
return false;
};
};
}
} /// 开启日志打印
void openLog() {
//true 开启日志
_dio.interceptors.add(LogInterceptor(responseBody: true));
} /// 请求类
Future<T> request<T>(
String path, {
DioMethod method = DioMethod.get,
Map<String, dynamic>? params,
data,
CancelToken? cancelToken,
Options? options,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
const _methodValues = {
DioMethod.get: 'get',
DioMethod.post: 'post',
DioMethod.put: 'put',
DioMethod.delete: 'delete',
DioMethod.patch: 'patch',
DioMethod.head: 'head'
}; options ??= Options(method: _methodValues[method]);
try {
Response response;
response = await _dio.request(path,
data: data,
queryParameters: params,
cancelToken: cancelToken ?? _cancelToken,
options: options,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress);
return response.data;
} on DioError catch (e) {
throw e;
}
} /// 取消网络请求
void cancelRequests({CancelToken? token}) {
token ?? _cancelToken.cancel("cancelled");
}
}

dio_transformer.dart

import 'dart:async';
import 'package:dio/dio.dart'; class DioTransformer extends DefaultTransformer {
@override
Future<String> transformRequest(RequestOptions options) async {
// 如果请求的数据接口是List<String>那我们直接抛出异常
if (options.data is List<String>) {
throw DioError(
error: "你不能直接发送List数据到服务器",
requestOptions: options,
);
} else {
return super.transformRequest(options);
}
} @override
Future transformResponse(
RequestOptions options, ResponseBody response) async {
// 例如我们响应选项里面没有自定义某些头部数据,那我们就可以自行添加
options.extra['myHeader'] = 'abc';
return super.transformResponse(options, response);
}
}

dio_token_interceptors.dart

import 'package:dio/dio.dart';
import 'package:tomato/page/dio/dio_util.dart'; class DioTokenInterceptors extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (options.headers['refreshToken'] == null) {
DioUtil.getInstance()?.dio.lock();
Dio _tokenDio = Dio();
_tokenDio
..get("http://localhost:8080/getRefreshToken").then((d) {
options.headers['refreshToken'] = d;
handler.next(options);
}).catchError((error, stackTrace) {
handler.reject(error, true);
}).whenComplete(() {
DioUtil.getInstance()?.dio.unlock();
}); // unlock the dio
} else {
options.headers['refreshToken'] = options.headers['refreshToken'];
handler.next(options);
}
} @override
void onResponse(Response response, ResponseInterceptorHandler handler) async {
// 响应前需要做刷新token的操作 super.onResponse(response, handler);
} @override
void onError(DioError err, ErrorInterceptorHandler handler) {
super.onError(err, handler);
}
}

dio_response.dart

class DioResponse<T> {
/// 消息(例如成功消息文字/错误消息文字)
final String? message; /// 自定义code(可根据内部定义方式)
final int? code; /// 接口返回的数据
final T? data; /// 需要添加更多
/// ......... DioResponse({
this.message,
this.data,
this.code,
}); @override
String toString() {
StringBuffer sb = StringBuffer('{');
sb.write("\"message\":\"$message\"");
sb.write(",\"errorMsg\":\"$code\"");
sb.write(",\"data\":\"$data\"");
sb.write('}');
return sb.toString();
}
} class DioResponseCode {
/// 成功
static const int SUCCESS = 0; /// 错误
static const int ERROR = 1; /// 更多
}

dio_method.dart

enum DioMethod {
get,
post,
put,
delete,
patch,
head,
}

dio_interceptors.dart

import 'package:dio/dio.dart';
import 'package:tomato/page/dio/dio_response.dart'; class DioInterceptors extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// 对非open的接口的请求参数全部增加userId
if (!options.path.contains("open")) {
options.queryParameters["userId"] = "xxx";
} // 头部添加token
options.headers["token"] = "xxx"; // 更多业务需求 handler.next(options); // super.onRequest(options, handler);
} @override
void onResponse(Response response, ResponseInterceptorHandler handler) async {
// 请求成功是对数据做基本处理
if (response.statusCode == 200) {
response.data =
DioResponse(code: 0, message: "请求成功啦", data: response.data);
} else {
response.data =
DioResponse(code: 1, message: "请求失败啦", data: response.data);
} // 对某些单独的url返回数据做特殊处理
if (response.requestOptions.baseUrl.contains("???????")) {
//....
} // 根据公司的业务需求进行定制化处理 // 重点
handler.next(response);
} @override
void onError(DioError err, ErrorInterceptorHandler handler) {
switch (err.type) {
// 连接服务器超时
case DioErrorType.connectTimeout:
{
// 根据自己的业务需求来设定该如何操作,可以是弹出框提示/或者做一些路由跳转处理
}
break;
// 响应超时
case DioErrorType.receiveTimeout:
{
// 根据自己的业务需求来设定该如何操作,可以是弹出框提示/或者做一些路由跳转处理
}
break;
// 发送超时
case DioErrorType.sendTimeout:
{
// 根据自己的业务需求来设定该如何操作,可以是弹出框提示/或者做一些路由跳转处理
}
break;
// 请求取消
case DioErrorType.cancel:
{
// 根据自己的业务需求来设定该如何操作,可以是弹出框提示/或者做一些路由跳转处理
}
break;
// 404/503错误
case DioErrorType.response:
{
// 根据自己的业务需求来设定该如何操作,可以是弹出框提示/或者做一些路由跳转处理
}
break;
// other 其他错误类型
case DioErrorType.other:
{}
break;
}
super.onError(err, handler);
}
}

dio_cache_interceptors.dart

import 'dart:collection';
import 'package:dio/dio.dart';
import 'package:tomato/page/dio/dio_util.dart';
import 'package:shared_preferences/shared_preferences.dart'; class CacheObject {
CacheObject(this.response)
: timeStamp = DateTime.now().millisecondsSinceEpoch;
Response response;
int timeStamp; @override
bool operator ==(other) {
return response.hashCode == other.hashCode;
} @override
int get hashCode => response.realUri.hashCode;
} class DioCacheInterceptors extends Interceptor {
// 为确保迭代器顺序和对象插入时间一致顺序一致,我们使用LinkedHashMap
var cache = LinkedHashMap<String, CacheObject>();
// sp
SharedPreferences? preferences; @override
void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
if (!DioUtil.CACHE_ENABLE) return super.onRequest(options, handler);
// 是否刷新缓存
bool refresh = options.extra["refresh"] == true; if (refresh) {
// 删除本地缓存
delete(options.uri.toString());
}
// 只有get请求才开启缓存
if (options.extra["noCache"] != true &&
options.method.toLowerCase() == 'get') {
String key = options.extra["cacheKey"] ?? options.uri.toString();
var ob = cache[key];
if (ob != null) {
// 内存缓存
if ((DateTime.now().millisecondsSinceEpoch - ob.timeStamp) / 1000 <
DioUtil.MAX_CACHE_AGE) {
return handler.resolve(cache[key]!.response);
} else {
//若已过期则删除缓存,继续向服务器请求
cache.remove(key);
} // 磁盘缓存
}
}
super.onRequest(options, handler);
} @override
void onResponse(Response response, ResponseInterceptorHandler handler) {
// 把响应的数据保存到缓存
if (DioUtil.CACHE_ENABLE) {
_saveCache(response);
} super.onResponse(response, handler);
} @override
void onError(DioError err, ErrorInterceptorHandler handler) {
// TODO: implement onError
super.onError(err, handler);
} _saveCache(Response object) {
RequestOptions options = object.requestOptions;
if (options.extra["noCache"] != true &&
options.method.toLowerCase() == "get") {
// 如果缓存数量超过最大数量限制,则先移除最早的一条记录
if (cache.length == DioUtil.MAX_CACHE_COUNT) {
cache.remove(cache[cache.keys.first]);
}
String key = options.extra["cacheKey"] ?? options.uri.toString();
cache[key] = CacheObject(object);
}
} void delete(String key) {
cache.remove(key);
}
}

使用方法

//包
import 'package:dio/dio.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:tomato/page/dio/dio_method.dart';
import 'package:tomato/page/dio/dio_response.dart';
import 'package:tomato/page/dio/dio_util.dart'; class DioUtilExample extends StatefulWidget {
@override
_DioUtilExampleState createState() => _DioUtilExampleState();
} class _DioUtilExampleState extends State<DioUtilExample> {
CancelToken _cancelToken = CancelToken(); void _handleLogin() async {
// 模拟用户退出页面
const _timeout = Duration(milliseconds: 2000);
Timer.periodic(_timeout, (timer) {
DioUtil().cancelRequests(token: _cancelToken); //定时取消请求
}); DioUtil().openLog(); //开启 DioUtil 内部日志输出
DioUtil.getInstance()?.openLog(); //获取单例并开启日志输出(如果单例不存在则返回 null)
DioUtil.CACHE_ENABLE = true; //开启缓存功能(默认关闭) //不发送参数
// DioUtil().setProxy(proxyAddress: "https://www.baidu.com", enable: true); //Http代理
// DioResponse result = await DioUtil().request("/book/book/getBookType", method: DioMethod.get, cancelToken: _cancelToken);
//发送这种的参数?letterId=&bookId=1
DioResponse result = await DioUtil().request(
//发送 GET 请求
"/Vocabulary/Vocabulary/getvocabularyType", //请求的接口路径
method: DioMethod.get, //请求的 HTTP 方法
params: {"letterId": 2, "bookId": 2}, //请求的参数
cancelToken: _cancelToken); ////请求的取消 Token // DioResponse result = await DioUtil().request(
// "/Vocabulary/Vocabulary/getvocabularyType",
// method: DioMethod.get,
// params: {"letterId": 2, "bookId": 2},
// cancelToken: _cancelToken);
print("^^^1^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1^^^");
print(result);
print("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
} @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("DioUtilExample"),
),
body: Center(
child: Column(
children: [
TextButton(
onPressed: _handleLogin,
child: Text("发送请求"),
),
],
),
),
);
}
}

Dio网络请求的更多相关文章

  1. Flutter -------- dio网络请求

    dio是Flutter中文网开源的一个强大的Dart Http请求库,支持Restful API.FormData.拦截器.请求取消.Cookie管理.文件上传/下载.超时等... 1.添加依赖# d ...

  2. flutter dio网络请求封装实现

    flutter dio网络请求封装实现 文章友情链接:   https://juejin.im/post/6844904098643312648 在Flutter项目中使用网络请求的方式大致可分为两种 ...

  3. Flutter之网络请求

    Flutter之网络请求 一,介绍与需求 1.1,介绍 1,http一个可组合的,基于Future的库,用于发出HTTP请求.包含一组高级功能和类,可轻松使用HTTP资源.它与平台无关,可以在命令行和 ...

  4. Flutter用dio封装http网络请求,设置统一的请求地址、headers及处理返回内容

    封装http请求是项目中经常需要做的,常用于设置通用请求地址.请求headers以及处理返回结果,例如在项目中开发地址.测试地址.上线地址是不一样的,当在封装的请求设置好默认地址之后只需要改一个地址而 ...

  5. Flutter学习(7)——网络请求框架Dio简单使用

    原文地址: Flutter学习(7)--网络请求框架Dio简单使用 | Stars-One的杂货小窝 Flutter系列学习之前都是在个人博客发布,感兴趣可以过去看看 网络请求一般APP都是需要的,在 ...

  6. 从零学习Fluter(五):Flutter中手势滑动拖动已经网络请求

    从六号开始搞Flutter,到今天写这篇blog已经过了4天时间,文档初步浏览了一遍,写下了这个demo.demo源码分享在github上,现在对flutter有种说不出的喜欢了.大家一起搞吧! 废话 ...

  7. Flutter网络请求与JSON解析

    本文介绍如何在Flutter中创建HTTP网络请求和对请求的json string进行类型解析. 网络请求 官方使用的是用dart io中的HttpClient发起的请求,但HttpClient本身功 ...

  8. 【dart学习】-- Dart之网络请求操作

    Flutter的请求网络有多种方式,一种是使用dart io中的HttpClient发起的请求,一种是使用dio库,另一种是使用http库,先学一下get和post,put.delete就等后面用到在 ...

  9. Flutter学习五之网络请求和轮播图的实现

    上期讲到了,怎样实现一个下拉刷新和加载更多的列表,数据更新,需要使用到网络请求,在flutter中,怎样实现一个网络请求呢?官方使用的是dart io中的HttpClient发起的请求,但HttpCl ...

  10. 【技术博客】Flutter—使用网络请求的页面搭建流程、State生命周期、一些组件的应用

    Flutter-使用网络请求的页面搭建流程.State生命周期.一些组件的应用 使用网络请求的页面搭建流程 ​ 在开发APP时,我们常常会遇到如下场景:进入一个页面后,要先进行网络调用,然后使用调用返 ...

随机推荐

  1. 【翻译】listener.ora

    今天仔细过一遍oracle的监听配置文件描述. cat $ORACLE_HOME/network/admin/samples/listener.ora # copyright (c) 1997 by ...

  2. P9140 [THUPC 2023 初赛] 背包

    prologue 这很难评(调了我 1h,我都想紫砂了. 还是典型得不重构就看不见系列. analysis 如果我们还是一个正常人,那么我们大体上是能看到题目的加粗字,这个格式很明显符合我们的同余最短 ...

  3. Java11配置maven

    这里假设Java11和maven都正确安装,使用的版本为Java11.maven3.6.1 测试环境变量 Java win + r 打开运行,输入 cmd,打开命令行提示符,输入java --vers ...

  4. python-手机自动化

    摘取:https://www.byhy.net/tut/auto/appium/01/ 用途和特点 Appium 是一个移动 App (手机应用)自动化工具. 手机APP 自动化有什么用? 自动化完成 ...

  5. day1 C语言:对于P1055 ISBN号码的代码优化及多解

    day1 C语言:对于P1055 ISBN号码的代码优化及多解 先看题目 直接说最优解,其他方法后置 第一部分 1.第一个点是数据的输入,本人第一的想法是直接用int类型去接受数据,但因为" ...

  6. P8741 [蓝桥杯 2021 省 B] 填空问题 题解

    P8741 [蓝桥杯 2021 省 B] 填空问题 题解 题目传送门 欢迎大家指出错误并联系这个蒟蒻 更新日志 2023-05-09 23:19 文章完成 2023-05-09 23:20 通过审核 ...

  7. python学习笔记(持续更新)

    一.对列表的操作 #建立一个列表 list = [1,2,3,4] #打印列表 print(list) #在列表尾部添加元素 list.append(5) #在指定位置插入元素 list.insert ...

  8. Bug是如何产生的?

    前言 知乎上有一个提问:Bug是如何产生的? ↓↓↓ 今天,我们就这个话题,一起来做个讨论. 个人觉得程序员与BUG的关系,就像空气中的细菌与人的关系一样. 我们不能完全杜绝与它接触,唯一能做的,就是 ...

  9. 你也许不再需要使用 CSS Media Queries(媒体查询)了

    你也许不再需要使用 CSS Media Queries(媒体查询)了 最近,CSS 引入了一项新功能:Container Queries.它可以替代 Media Queries 并实现 Media Q ...

  10. Util应用框架基础(二) - 对象到对象映射(AutoMapper)

    本节介绍Util应用框架相似对象之间的转换方法. 文章分为多个小节,如果对设计原理不感兴趣,只需阅读基础用法部分即可. 概述 现代化分层架构,普遍采用了构造块DTO(数据传输对象). DTO是一种参数 ...