在Flutter開發中,網絡請求是必不可少的功能。為了簡化代碼、提高開發效率,我們通常會封裝一個網絡請求工具類。本文基于Dio
庫,詳細介紹如何封裝一個高效、靈活、易用的網絡請求工具類,支持以下功能:
- 單例模式:確保全局只有一個
Dio
實例,避免資源浪費。 - 動態配置:支持運行時動態修改
baseUrl
、headers
等配置。 - 攔截器:內置日志攔截器,并支持添加自定義攔截器。
- 錯誤處理:提供詳細的錯誤信息,支持自定義錯誤處理邏輯。
- 文件上傳和下載:封裝了文件上傳和下載功能。
- 取消請求:支持取消正在進行的請求。
- 模塊化設計:代碼結構清晰,便于維護和擴展。
通過本文,你將學會如何封裝一個功能強大的網絡請求工具類,并直接應用到你的Flutter項目中。
代碼實現
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';class HttpUtil {// 單例模式static final HttpUtil _instance = HttpUtil._internal();factory HttpUtil() => _instance;HttpUtil._internal() {_init();}late Dio _dio;final List<Interceptor> _interceptors = []; // 自定義攔截器列表CancelToken _cancelToken = CancelToken(); // 用于取消請求// 初始化void _init() {_dio = Dio(BaseOptions(baseUrl: 'https://your-api-url.com', // 默認基礎地址connectTimeout: const Duration(seconds: 5), // 連接超時時間receiveTimeout: const Duration(seconds: 5), // 接收數據超時時間headers: {'Content-Type': 'application/json; charset=UTF-8',},));// 添加默認攔截器_dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {if (kDebugMode) {print('Request: ${options.method} ${options.path}');}return handler.next(options);},onResponse: (response, handler) {if (kDebugMode) {print('Response: ${response.statusCode} ${response.data}');}return handler.next(response);},onError: (DioException e, handler) {if (kDebugMode) {print('Error: ${e.message}');}return handler.next(e);},));// 添加自定義攔截器for (var interceptor in _interceptors) {_dio.interceptors.add(interceptor);}}// 添加自定義攔截器void addInterceptor(Interceptor interceptor) {_interceptors.add(interceptor);_dio.interceptors.add(interceptor);}// 動態更新基礎配置void updateBaseConfig({String? baseUrl,Duration? connectTimeout,Duration? receiveTimeout,Map<String, dynamic>? headers,}) {_dio.options.baseUrl = baseUrl ?? _dio.options.baseUrl;_dio.options.connectTimeout = connectTimeout ?? _dio.options.connectTimeout;_dio.options.receiveTimeout = receiveTimeout ?? _dio.options.receiveTimeout;_dio.options.headers = headers ?? _dio.options.headers;}// GET請求Future<Response> get(String path, {Map<String, dynamic>? queryParameters,Options? options,CancelToken? cancelToken,}) async {return _request(path,method: 'GET',queryParameters: queryParameters,options: options,cancelToken: cancelToken,);}// POST請求Future<Response> post(String path, {dynamic data,Map<String, dynamic>? queryParameters,Options? options,CancelToken? cancelToken,}) async {return _request(path,method: 'POST',data: data,queryParameters: queryParameters,options: options,cancelToken: cancelToken,);}// PUT請求Future<Response> put(String path, {dynamic data,Map<String, dynamic>? queryParameters,Options? options,CancelToken? cancelToken,}) async {return _request(path,method: 'PUT',data: data,queryParameters: queryParameters,options: options,cancelToken: cancelToken,);}// DELETE請求Future<Response> delete(String path, {dynamic data,Map<String, dynamic>? queryParameters,Options? options,CancelToken? cancelToken,}) async {return _request(path,method: 'DELETE',data: data,queryParameters: queryParameters,options: options,cancelToken: cancelToken,);}// 文件上傳Future<Response> upload(String path, {required String filePath,Map<String, dynamic>? data,Map<String, dynamic>? queryParameters,Options? options,CancelToken? cancelToken,}) async {final formData = FormData.fromMap({...data ?? {},'file': await MultipartFile.fromFile(filePath),});return _request(path,method: 'POST',data: formData,queryParameters: queryParameters,options: options,cancelToken: cancelToken,);}// 文件下載Future<Response> download(String urlPath,String savePath, {Map<String, dynamic>? queryParameters,Options? options,CancelToken? cancelToken,}) async {try {final response = await _dio.download(urlPath,savePath,queryParameters: queryParameters,options: options,cancelToken: cancelToken ?? _cancelToken,);return response;} on DioException catch (e) {throw _handleError(e);}}// 通用請求方法Future<Response> _request(String path, {required String method,dynamic data,Map<String, dynamic>? queryParameters,Options? options,CancelToken? cancelToken,}) async {try {final response = await _dio.request(path,data: data,queryParameters: queryParameters,options: Options(method: method),cancelToken: cancelToken ?? _cancelToken,);return response;} on DioException catch (e) {throw _handleError(e);}}// 取消請求void cancelRequests({CancelToken? cancelToken}) {if (cancelToken == null) {_cancelToken.cancel('Request cancelled');_cancelToken = CancelToken(); // 重置CancelToken} else {cancelToken.cancel('Request cancelled');}}// 錯誤處理String _handleError(DioException e) {switch (e.type) {case DioExceptionType.connectionTimeout:return '連接超時';case DioExceptionType.sendTimeout:return '發送請求超時';case DioExceptionType.receiveTimeout:return '接收數據超時';case DioExceptionType.badResponse:return '服務器返回錯誤: ${e.response?.statusCode}';case DioExceptionType.cancel:return '請求已取消';case DioExceptionType.unknown:return '未知錯誤: ${e.message}';default:return '網絡錯誤: ${e.message}';}}
}
使用示例
void fetchData() async {try {final response = await HttpUtil().get('/api/data');print('Data: ${response.data}');} catch (e) {print('Error: $e');}
}void uploadFile() async {try {final response = await HttpUtil().upload('/api/upload',filePath: '/path/to/file',);print('Upload Response: ${response.data}');} catch (e) {print('Error: $e');}
}void cancelRequest() {HttpUtil().cancelRequests();
}
總結
通過封裝這樣一個網絡請求工具類,我們可以顯著提高Flutter項目的開發效率,減少重復代碼,同時增強代碼的可維護性和擴展性。希望本文對你有所幫助