Flutter 网络请求与数据处理:从基础到单例封装

Flutter 网络请求与数据处理:从基础到单例封装

在 Flutter 开发中,网络请求是一个非常常见的需求,比如获取 API 数据、上传文件、处理分页加载等。为了高效地处理网络请求和数据管理,我们需要选择合适的工具并进行合理的封装。

本篇博客将详细介绍 Flutter 中网络请求的基础知识、常用库(如 httpdio),并最终实现一个单例模式的网络请求封装,帮助你在项目中高效管理网络请求。


1. 网络请求的基础知识

1.1 HTTP 请求的基本类型

  1. GET:从服务器获取数据。
  2. POST:向服务器发送数据。
  3. PUT:更新服务器上的数据。
  4. DELETE:删除服务器上的数据。

1.2 常用的网络请求库

  1. http
    • Flutter 官方提供的轻量级 HTTP 客户端。
    • 适合简单的网络请求。
  2. dio
    • 功能强大的第三方库,支持拦截器、文件上传下载、请求取消等。
    • 适合复杂的网络请求场景。

2. 使用 http 进行网络请求

2.1 安装 http

pubspec.yaml 中添加依赖:

yaml 复制代码
dependencies:
  http: ^0.15.0

运行以下命令安装依赖:

bash 复制代码
flutter pub get

2.2 基本用法

GET 请求
dart 复制代码
import 'dart:convert';
import 'package:http/http.dart' as http;

void fetchData() async {
  final url = Uri.parse("https://jsonplaceholder.typicode.com/posts");
  final response = await http.get(url);

  if (response.statusCode == 200) {
    final data = json.decode(response.body);
    print("数据加载成功:$data");
  } else {
    print("请求失败,状态码:${response.statusCode}");
  }
}

void main() {
  fetchData();
}
POST 请求
dart 复制代码
void postData() async {
  final url = Uri.parse("https://jsonplaceholder.typicode.com/posts");
  final response = await http.post(
    url,
    headers: {"Content-Type": "application/json"},
    body: json.encode({"title": "Flutter", "body": "Hello World", "userId": 1}),
  );

  if (response.statusCode == 201) {
    final data = json.decode(response.body);
    print("数据提交成功:$data");
  } else {
    print("请求失败,状态码:${response.statusCode}");
  }
}

void main() {
  postData();
}

3. 使用 dio 进行网络请求

3.1 安装 dio

pubspec.yaml 中添加依赖:

yaml 复制代码
dependencies:
  dio: ^5.0.0

运行以下命令安装依赖:

bash 复制代码
flutter pub get

3.2 基本用法

GET 请求
dart 复制代码
import 'package:dio/dio.dart';

void fetchData() async {
  final dio = Dio();
  final response = await dio.get("https://jsonplaceholder.typicode.com/posts");

  if (response.statusCode == 200) {
    print("数据加载成功:${response.data}");
  } else {
    print("请求失败,状态码:${response.statusCode}");
  }
}

void main() {
  fetchData();
}
POST 请求
dart 复制代码
void postData() async {
  final dio = Dio();
  final response = await dio.post(
    "https://jsonplaceholder.typicode.com/posts",
    data: {"title": "Flutter", "body": "Hello World", "userId": 1},
  );

  if (response.statusCode == 201) {
    print("数据提交成功:${response.data}");
  } else {
    print("请求失败,状态码:${response.statusCode}");
  }
}

void main() {
  postData();
}

3.3 使用拦截器

dio 提供了强大的拦截器功能,可以在请求前后进行统一处理。

示例:添加拦截器
dart 复制代码
void fetchDataWithInterceptor() async {
  final dio = Dio();

  // 添加拦截器
  dio.interceptors.add(InterceptorsWrapper(
    onRequest: (options, handler) {
      print("请求开始:${options.uri}");
      return handler.next(options);
    },
    onResponse: (response, handler) {
      print("请求成功:${response.data}");
      return handler.next(response);
    },
    onError: (error, handler) {
      print("请求失败:${error.message}");
      return handler.next(error);
    },
  ));

  final response = await dio.get("https://jsonplaceholder.typicode.com/posts");
  print(response.data);
}

void main() {
  fetchDataWithInterceptor();
}

4. 单例模式封装网络请求

在实际项目中,网络请求通常需要统一管理,比如设置基础 URL、添加拦截器、处理错误等。通过单例模式封装网络请求,可以提高代码的复用性和可维护性。

4.1 单例封装 dio

封装代码
dart 复制代码
import 'package:dio/dio.dart';

class DioClient {
  // 单例模式
  static final DioClient _instance = DioClient._internal();
  factory DioClient() => _instance;

  late Dio _dio;

  DioClient._internal() {
    _dio = Dio(BaseOptions(
      baseUrl: "https://jsonplaceholder.typicode.com",
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10),
      headers: {"Content-Type": "application/json"},
    ));

    // 添加拦截器
    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        print("请求开始:${options.uri}");
        return handler.next(options);
      },
      onResponse: (response, handler) {
        print("请求成功:${response.data}");
        return handler.next(response);
      },
      onError: (error, handler) {
        print("请求失败:${error.message}");
        return handler.next(error);
      },
    ));
  }

  // GET 请求
  Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) async {
    return await _dio.get(path, queryParameters: queryParameters);
  }

  // POST 请求
  Future<Response> post(String path, {Map<String, dynamic>? data}) async {
    return await _dio.post(path, data: data);
  }

  // PUT 请求
  Future<Response> put(String path, {Map<String, dynamic>? data}) async {
    return await _dio.put(path, data: data);
  }

  // DELETE 请求
  Future<Response> delete(String path, {Map<String, dynamic>? data}) async {
    return await _dio.delete(path, data: data);
  }
}

4.2 使用封装的 DioClient

GET 请求
dart 复制代码
void fetchData() async {
  final dioClient = DioClient();
  final response = await dioClient.get("/posts");

  if (response.statusCode == 200) {
    print("数据加载成功:${response.data}");
  } else {
    print("请求失败,状态码:${response.statusCode}");
  }
}

void main() {
  fetchData();
}
POST 请求
dart 复制代码
void postData() async {
  final dioClient = DioClient();
  final response = await dioClient.post(
    "/posts",
    data: {"title": "Flutter", "body": "Hello World", "userId": 1},
  );

  if (response.statusCode == 201) {
    print("数据提交成功:${response.data}");
  } else {
    print("请求失败,状态码:${response.statusCode}");
  }
}

void main() {
  postData();
}

5. 总结

5.1 httpdio 的对比

特性 http dio
功能 轻量级,适合简单请求 功能强大,支持拦截器、文件上传等
学习曲线
扩展性 较低
适用场景 小型项目 中型和大型项目

5.2 实践建议

  1. 小型项目
    • 使用 http,简单易用。
  2. 中型和大型项目
    • 使用 dio,并通过单例模式封装,统一管理网络请求。
相关推荐
程序员Ctrl喵9 小时前
异步编程:Event Loop 与 Isolate 的深层博弈
开发语言·flutter
前端不太难10 小时前
Flutter 如何设计可长期维护的模块边界?
flutter
小蜜蜂嗡嗡11 小时前
flutter列表中实现置顶动画
flutter
始持12 小时前
第十二讲 风格与主题统一
前端·flutter
始持12 小时前
第十一讲 界面导航与路由管理
flutter·vibecoding
始持12 小时前
第十三讲 异步操作与异步构建
前端·flutter
新镜12 小时前
【Flutter】 视频视频源横向、竖向问题
flutter
黄林晴13 小时前
Compose Multiplatform 1.10 发布:统一 Preview、Navigation 3、Hot Reload 三箭齐发
android·flutter
Swift社区13 小时前
Flutter 应该按功能拆,还是按技术层拆?
flutter
肠胃炎14 小时前
树形选择器组件封装
前端·flutter