Flutter Dio 网络请求详解:企业级 HTTP 客户端

Flutter Dio 网络请求详解:企业级 HTTP 客户端

文章总体概览信息图

引言

在 Flutter 开发中,网络请求是不可或缺的一部分。Dio 是一个强大的 HTTP 客户端库,支持拦截器、全局配置、FormData、文件上传下载等功能,是 Flutter 社区最受欢迎的网络请求库之一。

Dio 基础用法

安装依赖

dependencies:
  dio: ^5.0.0

创建 Dio 实例

import 'package:dio/dio.dart';

final dio = Dio();

基本 GET 请求

void fetchData() async {
  try {
    final response = await dio.get('https://api.example.com/data');
    print(response.data);
  } catch (e) {
    print('Error: $e');
  }
}

基本 POST 请求

void postData() async {
  try {
    final response = await dio.post(
      'https://api.example.com/data',
      data: {
        'name': 'John',
        'age': 30,
      },
    );
    print(response.data);
  } catch (e) {
    print('Error: $e');
  }
}

高级配置

全局配置

final dio = Dio(BaseOptions(
  baseUrl: 'https://api.example.com',
  connectTimeout: const Duration(seconds: 5),
  receiveTimeout: const Duration(seconds: 3),
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token',
  },
));

请求配置

final response = await dio.get(
  '/users',
  queryParameters: {'page': 1, 'limit': 10},
  options: Options(
    method: 'GET',
    headers: {'Custom-Header': 'value'},
    responseType: ResponseType.json,
  ),
);

拦截器

请求拦截器

dio.interceptors.add(InterceptorsWrapper(
  onRequest: (options, handler) {
    print('Request: ${options.method} ${options.path}');
    options.headers['Authorization'] = 'Bearer token';
    return handler.next(options);
  },
));

响应拦截器

dio.interceptors.add(InterceptorsWrapper(
  onResponse: (response, handler) {
    print('Response: ${response.statusCode}');
    return handler.next(response);
  },
));

错误拦截器

dio.interceptors.add(InterceptorsWrapper(
  onError: (DioException e, handler) {
    print('Error: ${e.response?.statusCode}');
    return handler.next(e);
  },
));

重试拦截器

dio.interceptors.add(RetryInterceptor(
  dio: dio,
  retries: 3,
  retryDelay: const Duration(seconds: 1),
));

文件上传与下载

文件上传

void uploadFile() async {
  final formData = FormData.fromMap({
    'file': await MultipartFile.fromFile(
      '/path/to/file.jpg',
      filename: 'photo.jpg',
    ),
    'description': 'A beautiful photo',
  });

  try {
    final response = await dio.post(
      '/upload',
      data: formData,
      onSendProgress: (sent, total) {
        print('Progress: ${(sent / total * 100).toStringAsFixed(0)}%');
      },
    );
    print(response.data);
  } catch (e) {
    print('Error: $e');
  }
}

文件下载

void downloadFile() async {
  try {
    final response = await dio.download(
      'https://example.com/file.pdf',
      '/path/to/save/file.pdf',
      onReceiveProgress: (received, total) {
        print('Progress: ${(received / total * 100).toStringAsFixed(0)}%');
      },
    );
    print('Download completed');
  } catch (e) {
    print('Error: $e');
  }
}

取消请求

CancelToken cancelToken = CancelToken();

void fetchData() async {
  try {
    final response = await dio.get(
      '/data',
      cancelToken: cancelToken,
    );
    print(response.data);
  } catch (e) {
    if (e is DioException && e.type == DioExceptionType.cancel) {
      print('Request cancelled');
    }
  }
}

// 取消请求
cancelToken.cancel('Request cancelled by user');

封装最佳实践

创建 API 服务类

class ApiService {
  late Dio _dio;

  ApiService() {
    _dio = Dio(BaseOptions(
      baseUrl: 'https://api.example.com',
      connectTimeout: const Duration(seconds: 5),
      receiveTimeout: const Duration(seconds: 3),
    ));

    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        options.headers['Authorization'] = 'Bearer ${getToken()}';
        return handler.next(options);
      },
      onError: (e, handler) {
        if (e.response?.statusCode == 401) {
          // 处理未授权
          refreshToken();
        }
        return handler.next(e);
      },
    ));
  }

  Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) {
    return _dio.get(path, queryParameters: queryParameters);
  }

  Future<Response> post(String path, {dynamic data}) {
    return _dio.post(path, data: data);
  }

  Future<Response> put(String path, {dynamic data}) {
    return _dio.put(path, data: data);
  }

  Future<Response> delete(String path) {
    return _dio.delete(path);
  }
}

模型转换

class User {
  final String id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
    };
  }
}

class UserRepository {
  final ApiService apiService;

  UserRepository(this.apiService);

  Future<User> getUser(String id) async {
    final response = await apiService.get('/users/$id');
    return User.fromJson(response.data);
  }

  Future<List<User>> getUsers() async {
    final response = await apiService.get('/users');
    return (response.data as List).map((json) => User.fromJson(json)).toList();
  }
}

错误处理

统一错误处理

class ApiException implements Exception {
  final String message;
  final int? statusCode;

  ApiException({required this.message, this.statusCode});
}

Future<T> safeApiCall<T>(Future<Response> Function() apiCall) async {
  try {
    final response = await apiCall();
    return response.data as T;
  } on DioException catch (e) {
    throw ApiException(
      message: e.message ?? 'Unknown error',
      statusCode: e.response?.statusCode,
    );
  }
}

测试支持

Mock 请求

void main() {
  late Dio dio;
  late ApiService apiService;

  setUp(() {
    dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
    apiService = ApiService();
  });

  test('get user', () async {
    final user = await apiService.getUser('1');
    expect(user.id, '1');
  });
}

性能优化

请求缓存

dio.interceptors.add(CacheInterceptor());

连接池

final dio = Dio(BaseOptions(
  baseUrl: 'https://api.example.com',
  connectTimeout: const Duration(seconds: 5),
));

dio.httpClientAdapter = HttpClientAdapter(
  ConnectionManager(
    idleTimeout: const Duration(seconds: 30),
    maxConnections: 10,
  ),
);

总结

Dio 是一个功能强大的 HTTP 客户端库,提供了丰富的功能和良好的扩展性。通过合理使用拦截器、封装 API 服务和错误处理,我们可以构建健壮的网络请求层。

掌握 Dio 后,你可以:

  • 轻松发起各种 HTTP 请求
  • 实现请求拦截和响应处理
  • 上传和下载文件
  • 取消请求
  • 构建可测试的网络层

Dio 是 Flutter 网络请求的首选方案,值得深入学习和使用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值