Flutter Series 08: Network Requests with Http and Dio

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');    }

Leave a Comment