Flutter 第七课 --- flutter 网络封装

258 阅读3分钟

启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

Flutter系列文章列表

  1. 2022年了,你还不会flutter!!!
  2. Flutter 第一课---flutter特点及组件开发
  3. Flutter 第二课---组件生命周期和App生命周期
  4. Flutter 第三课---状态管理之Provide
  5. Flutter 第四课---路由管理
  6. Flutter 第五课 --- 包管理器和资源管理
  7. Flutter 第六课 --- flutter网络请求

为什么需要封装Dio?

在上一节课中,我们对比了三种网络请求的方式,发现Dio已经足够易用,之所以有想法去封装是想让请求流程更加统一,比如load、错误请求以及成功、失败情况下统一处理,传入参数可能会比较多,导致方法看起来会很臃肿。所以自己进行了封装和改善。而且封装代码有如下优点:

  • 统一请求流程
  • 统一响应处理,200情况下的api不同情况的处理
  • 统一ERROR处理
  • 针对拦截器、缓存、统一处理错误等多个配置进行统一管理

对Dio请求进行初始化

首先对连结超时时间 、响应超时时间 、BaseUrl 进行统一设置

import 'package:dio/dio.dart';

class Request {
  // 配置 Dio 实例
  static final BaseOptions _options = BaseOptions(
    baseUrl: 'https://test.com',
    connectTimeout: 10000,  // 连接超时时间
    receiveTimeout: 10000,  // 响应超时时间
  );
  
// 声明Dio变量
Dio dio;

// 初始化dio
Dio dio = Dio(BaseOptions);
}

创建(GET、POST、PUT、DELETE)方法

class Request {
  static Future<T> get<T>(String path, {params}) {
    return _request(path, method: 'get', queryParameters: params);
}

static Future<T> post<T>(String path, {params, data}) {
    return _request(path, method: 'post', queryParameters: params, data: data);
}

static Future<T> delete<T>(String path, {params, data}) {
    return _request(path, method: 'delete', queryParameters: params);
}

static Future<T> put<T>(String path, {params, data}) {
    return _request(path, method: 'put', queryParameters: params, data: data);
}
}

Restful APi封装

因为不管是get()还是post()请求,Dio 内部最终都会调用request 方法,_request 是核心函数,所有的请求都会走这里。

// _request 是核心函数,所有的请求都会走这里
static Future<T> _request<T>(String path, {required String method, queryParameters, data}) async {
    if (queryParameters != null) {
      var params = '';
      queryParameters.forEach((key, value) {
        if (!path.contains(key)) {
          params += key + '=' + value.toString() + '&';
        }
      });

      var url = params.substring(0, params.length - 1);
      path += '?$url';
      print(path);
    }

    try {
      Response response = await _dio.request(path, data: data, options: Options(method: method));
      if (response.statusCode == 200 || response.statusCode == 201) {
        if (response.data is Map) {
          return response.data;
        } else {
          return json.decode(response.data.toString());
        }
      } else {
        EasyLoading.dismiss();
        return Future.error('HTTP错误');
      }
    } on DioError catch (e) {
      EasyLoading.dismiss();
      print("错误状态码${e.response?.statusCode},错误消息${e.response?.statusMessage}");
    }
    return Future.error('HTTP错误');
  }

至此一个最基本的网络请求就完成了,如何调用,我们只需要在用到网络请求的组件中,调用类对应的请求方式即可,如下是一个用户名登录流程

// (1) 导入Restful api
import '../utils/dio_request.dart';
// (2) 封住用户登录api
class UserLogin {
  static getUserLogin(name) {
    return Request.get(
      '/user/wq',
      params: {},
    );
  }
}
//  用户名登录流程
userNameLogin() async {
  String username = _controller.text;
  EasyLoading.show(status: 'loading...');
  var result = await UserLogin.getUserLogin(username);
  print("拿到用户信息")
}

封装拦截器

在开发的过程中,需要在请求前、响应前、错误时对某一些接口做特殊的处理,那我们就需要用到拦截器。这时候需要创建一个继承Interceptor的接口:

import 'package:dio/dio.dart';
import 'package:flutter_dio/dio_util/dio_response.dart';

class DioInterceptors extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    // 头部添加token
    options.headers["token"] = "xxx";
    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    // 请求成功是对数据做基本处理
    if (response.statusCode == 200) {
      response.data = DioResponse(code: 0, message: "请求成功啦", data: response);
    } else {
      response.data = DioResponse(code: 1, message: "请求失败啦", data: response);
    }
  }
}

如上是对请求前增加token以及请求成功失败的错误处理。更多详情配置清查阅dio官方文档

结束语

关于flutter网络封装的学习到这里就结束了。下期我们来说说flutter原生转web的学习。如果你刚好正在学习flutter,可以关注我,请相信会给你不一样的收获。如果你是flutter大佬,欢迎指导!