Flutter comes with a built-in HTTP request library, while the third-party library that is more commonly used is Dio (as okhttp does not have a Dart version).1. Selection Criteria1. PerformanceBoth are based on Dart’s HttpClient at the core, and the actual request speed difference is minimal.2. Package SizeThe http package introduces approximately 60KB of .dex files.Dio, due to its rich functionality, increases the package size by about 3.2MB for the core engine and 1.25MB for framework code.3. Large File HandlinghttpDownloading large files can easily lead to overflow.Dio supports streaming downloads (to avoid memory issues), file chunk uploads, andresume support.4. Custom Header Configurationhttpdoes not have a global reuse mechanism, requiring explicit header settings for each request. -> A custom HTTP utility class can be encapsulated to simplify this.Dioallows setting common headers through BaseOptions, shared across all requests; it also supports overriding global configurations in individual request options, providing greater flexibility.5. Parameter ComplexityThe differences between the two are minimal.6. Logginghttp requires manual logging.Dioautomatically formats logs through interceptors like LogInterceptor or PrettyDioLogger, outputting request details, response times, etc.;it also supports proxy configuration (for easier packet capture debugging).7. Secondary EncapsulationBoth can be encapsulated using the singleton pattern, as well as encapsulating baseUrl, headers, parameters, etc., to increase usability.2. Basic Usage ComparisonBelow are some comparisons of the two in basic usage (without secondary encapsulation):1. GET Request
final extraHeaders = {'test': '111'}; // Custom Header final queryParams = {'page': '1', 'per_page': '10'}; // Request parameters const urlRepo = "https://api.github.com/users/flutter/repos"; final urlGet = Uri.parse(urlRepo).replace(queryParameters: queryParams);
//Http print('Response: $urlGet'); final response = await http.get(urlGet, headers: extraHeaders); if (response.statusCode == 200) { print('Response: ${response.body}'); final List<dynamic> dataList = jsonDecode(response.body); // Data conversion print('Response: id=${dataList[1]["id"]}'); } else { print('Response-error'); }
//Dio final responseDio = await Dio().get(urlRepo, queryParameters: queryParams, options: Options( headers: extraHeaders, responseType: ResponseType.json, )); if (responseDio.statusCode == 200) { print('DioResponse: ${responseDio.data}'); final List<dynamic> dataList = responseDio.data; // Specify responseType: ResponseType.json, no need to convert again print('DioResponse: id=${dataList[1]["id"]}'); } else { print('DioResponse-error'); }
Dio can automatically parse data types through the responseType attribute in the Options parameter:
-
ResponseType.json: default value, automatically converts the response body to Map<String, dynamic> or List<dynamic>
-
ResponseType.plain: returns the raw text as a String, without any parsing
-
ResponseType.stream: receives response data in a stream format, returning a ResponseBody stream object
-
ResponseType.bytes: returns a Uint8List type binary byte array
2. POST Request
final extraHeaders = { 'Authorization': 'Bearer ghp_xxxxxx', 'Accept': 'application/vnd.github.v3+json', }; // Custom Header const urlRepo = "https://api.github.com/repos/{user}/{repo}/issues"; final url = Uri.parse(urlRepo); final body = { 'title': 'testIssues', 'body': 'Detailed reproduction steps...', 'labels': ['test', 'issues'], }; print('post: $urlRepo');
//【Http】 final response = await http.post( url, headers: extraHeaders, body: jsonEncode(body), ); print('response: ${response.statusCode}'); if (response.statusCode == 200 || response.statusCode == 201) { print('response: ${response.body}'); } else { print('Response-error'); }
//【Dio】 final responseDio = await Dio().post(urlRepo, data: body, options: Options( headers: extraHeaders, responseType: ResponseType.plain, // Returns raw data )); print('response: ${responseDio.statusCode}'); if (responseDio.statusCode == 200 || responseDio.statusCode == 201) { print('DioResponse: ${responseDio.data}'); } else { print('DioResponse-error'); }
3. File Upload
final extraHeaders = { 'Authorization': 'Bearer ghp_xxxxxx', 'Accept': 'application/vnd.github.v3+json', }; // Custom Header const urlRepo = "https://api.github.com/repos/{user}/{repo}/contents/files/testUpload1.txt"; String? fileSha = null; final fileBytes = await rootBundle.load("assets/testUpload.txt"); final base64Content = base64Encode(fileBytes.buffer.asUint8List()); final body = { 'message': 'Upload file', 'content': base64Content, if (fileSha != null) 'sha': fileSha // Required for updates, can be omitted for new uploads }; print('post: $urlRepo');
//【Http】 final response = await http.put( Uri.parse(urlRepo), headers: extraHeaders, body: jsonEncode(body), ); print('response: ${response.statusCode}'); if (response.statusCode == 200 || response.statusCode == 201) { print('response: ${response.body}'); } else { print('Response-error'); }
//【Dio】 final responseDio = await Dio().put(urlRepo, data: body, options: Options( headers: extraHeaders, responseType: ResponseType.json, // Returns raw data )); print('DioResponse: ${responseDio.statusCode}'); if (responseDio.statusCode == 200 || responseDio.statusCode == 201) { print('DioResponse: ${responseDio.data}'); } else { print('DioResponse-error'); }
4. File Download and Progress
var urlRepo = "https://file.dircleaner.com/apk/dircleaner_2.1.3.apk"; // Get storage path final saveDir = await getExternalStorageDirectory(); final saveFile = File('${saveDir?.path}/test.apk'); print('Download started: $urlRepo');
// 【Http】 final client = http.Client(); final request = http.Request('GET', Uri.parse(urlRepo)); final response = await client.send(request); // Get total file size final totalBytes = response.contentLength ?? 0; int receivedBytes = 0; final sink = saveFile.openWrite(); // Handle byte stream response.stream.listen( (chunk) { receivedBytes += chunk.length; print('Download progress: $receivedBytes/$totalBytes -> ${saveFile.path}'); sink.add(chunk); }, onDone: () { sink.close(); client.close(); print('Download completed: ${saveFile.path}'); }, onError: (e) { client.close(); print('Download failed: $e'); }, );
///【Dio】 try { await Dio().download( urlRepo, saveFile.path, onReceiveProgress: (received, total) { print('Dio download progress: $received/$total -> ${saveFile.path}'); }, options: Options( headers: {'User-Agent': 'Flutter-App'}, // Some servers require UA header receiveTimeout: const Duration(minutes: 5), // Extend timeout for large files ), ); print('Dio download completed: $saveFile'); } on DioException catch (e) { print('Dio download failed: $e'); }