openplanning

Hướng dẫn và ví dụ Dart Dio

  1. Cài đặt thư viện
  2. CrudDemoServer
  3. Dio Constructor
  4. Tạo đối tượng Dio
  5. Dio GET
  6. Dio GET Example
  7. Dio POST
  8. Dio POST Example
  9. Dio PUT
  10. Dio PUT Example
  11. Dio DELETE
  12. Dio DELETE Example
  13. Các bài viết liên quan
Dio là một thư viện HTTP Client mạnh mẽ cho Dart/Flutter. Dio được xây dựng phía trên gói http tiêu chuẩn của Dart, với các tính năng bổ xung khiến nó trở lên mạnh và linh hoạt hơn:
  • Interceptors
  • Request cancellation
  • Request Retry
Các tham số được sử dụng trong các phương thức của lớp Dio và mô tả của chúng:
queryParameters
Chỉ định các "Query parameters" (Tham số truy vấn) bao gồm trong URL của yêu cầu.
options
Options options
data
Chỉ định dữ liệu bao gồm trong phần thân của yêu cầu. Kiểu dữ liệu có thể là:
  • String, Map<String,dynamic>, List<dynamic>, FormData, MultipartFile
cancelToken
Một đối tượng được sử dụng để huỷ yêu cầu. Khi yêu cầu bị huỷ CancelTokenException sẽ được ném ra.
final cancelToken = CancelToken();
onSendProgress
Một hàm callback được gọi trong quá trình dữ liệu đang được gửi đi. Hàm này có ích trong trường hợp upload dữ liệu có dung lượng lớn.
typedef ProgressCallback = void Function(int count, int total);
onReceiveProgress
Một hàm callback được gọi trong quá trình dữ liệu đang được tải về. Hàm này có ích trong trường hợp downoad dữ liệu có dung lượng lớn.
typedef ProgressCallback = void Function(int count, int total);
Trong bài viết này chúng ta sẽ tìm hiểu về các tính năng cơ bản của gói Dio, các tính năng nâng cao sẽ được đề xuất trong các bài viết tách biệt ở cuối bài viết này.

1. Cài đặt thư viện

pubspec.yaml
dependencies:
  dio:  ^5.5.0+1

2. CrudDemoServer

Bài học này sử dụng một máy chủ mô phỏng CrudDemoServer. Bạn có thể download và cài đặt miễn phí theo liên kết dưới đây:
Sau khi đăng nhập thành công vào CrudDemoServer bạn sẽ nhận được một accessToken. Để có thể truy vấn, thêm, xoá và sửa các tài nguyên trên CrudDemoServer bạn cần đính kèm accessToken vào các yêu cầu.
_constants.dart
import 'dart:convert';

///
/// After successfully logging in, you will have accessToken.
/// Here is an example accessToken,
/// used for the examples in this lesson.
///
///  For example: YWRtaW46MTIz
///
String get accessToken { 
  String userName = "admin";
  String password = "123";
  String str = "$userName:$password";
  final bytes = utf8.encode(str);
  
  // YWRtaW46MTIz
  final base64Str = base64.encode(bytes);
  return base64Str;
}

3. Dio Constructor

Lớp Dio chỉ có một constructor duy nhất với một tham số tuỳ chọn.
Dio([BaseOptions? options])
Constructor của lớp BaseOptions:
BaseOptions({
  String? method,
  Duration? connectTimeout,
  Duration? receiveTimeout,
  Duration? sendTimeout,
  String baseUrl = '',
  Map<String, dynamic>? queryParameters,
  Map<String, dynamic>? extra,
  Map<String, dynamic>? headers,
  bool? preserveHeaderCase = false,
  ResponseType? responseType = ResponseType.json,
  String? contentType,
  bool Function(int?)? validateStatus,
  bool? receiveDataWhenStatusError,
  bool? followRedirects,
  int? maxRedirects,
  bool? persistentConnection,
  FutureOr<List<int>> Function(String, RequestOptions)? requestEncoder,
  FutureOr<String?> Function(List<int>, RequestOptions, ResponseBody)? responseDecoder,
  ListFormat? listFormat,
});

4. Tạo đối tượng Dio

Tạo một đối tượng Dio mặc định:
dio_ex1.dart
import 'package:dio/dio.dart';

// Create a Dio object:
final dio = Dio();

Future<void> main() async {
  var path =
      "https://raw.githubusercontent.com/o7planning/rs/master/dart/json/user-info-1.json";

  final response = await dio.get(path);
  print(response.data);
}
Output:
{
"userName": "tom",
"fullName": "Tom Cat",
"country": "America"
}
Dio(BaseOptions):
Ví dụ tiếp theo này, chúng ta sẽ tạo một đối tượng Dio với các tuỳ chọn cơ sở như baseUrl, connectTimeout, receiveTimeoutheaders.
connectTimeout
Thời gian tối đa chờ đợi kết nối, nếu quá thời gian này kết nối coi như bị thất bại.
receiveTimeout
Thời gian tối đa chờ đợi kết quả trả về từ máy chủ, nếu vượt quá thời gian này yêu cầu được coi là thất bại.
dio_ex2.dart
import 'package:dio/dio.dart';

// Create a Dio object with Base Options :
final dio = Dio(
  BaseOptions(
    baseUrl: 'https://raw.githubusercontent.com',
    connectTimeout: Duration(seconds: 5),
    receiveTimeout: Duration(seconds: 5),
    headers: {
      'Accept': 'application/json',
    },
  ),
);

Future<void> main() async {
  // url = baseUrl + path
  var path = "/o7planning/rs/master/dart/json/user-info-1.json";

  final response = await dio.get(path);
  print(response.data);
}
Sau khi tạo được đối tượng Dio với các tuỳ chọn cơ sở bạn có thể sử dụng nó để gửi các yêu cầu khác nhau tới máy chủ như GET, POST, PUT, PATCHDELETE. Về cơ bản, bạn có thể chỉ cần tạo một đối tượng Dio và sử dụng nó nhiều lần cho nhiều loại yêu cầu khác nhau.

5. Dio GET

Phương thức get() của lớp Dio được sử dụng để gửi một yêu cầu GET tới máy chủ để nhận về một tài nguyên.
dio.get()
Future<Response<T>> get<T>(
  String path, {
  Object? data,
  Map<String, dynamic>? queryParameters,
  Options? options,
  CancelToken? cancelToken,
  void Function(int, int)? onReceiveProgress,
});
queryParameters
Chỉ định các "Query parameters" (Tham số truy vấn) bao gồm trong URL của yêu cầu.
data
Chỉ định dữ liệu bao gồm trong phần thân của yêu cầu. Kiểu dữ liệu có thể là:
  • String, Map<String,dynamic>, List<dynamic>, FormData, MultipartFile
cancelToken
Một đối tượng được sử dụng để huỷ yêu cầu. Khi yêu cầu bị huỷ CancelTokenException sẽ được ném ra.
final cancelToken = CancelToken();
onReceiveProgress
Một hàm callback được gọi trong quá trình dữ liệu đang được tải về. Hàm này có ích trong trường hợp downoad dữ liệu có dung lượng lớn.
typedef ProgressCallback = void Function(int count, int total);

6. Dio GET Example

Ví dụ đơn giản, sử dụng Dio để gửi một yêu cầu GET tới máy chủ.
dio_get_ex1.dart
import 'package:dio/dio.dart';
import '_constants.dart';

// Create a Dio object with Base Options :
final dio = Dio(
  BaseOptions(
    // Please download and Install CrudDemoServer.
    baseUrl: 'http://localhost:8080',
    connectTimeout: Duration(seconds: 5),
    receiveTimeout: Duration(seconds: 5),
    headers: {
      'Accept': 'application/json',
    },
  ),
);

Future<void> main() async {
  Map<String, dynamic> headers = {
    'Authorization': 'Basic $accessToken', // <-----
  };
  //
  try {
    final response = await dio.get(
      '/rest/appUsers/search',
      options: Options(headers: headers),
      queryParameters: {
        'searchText': 'anony',
        'page': 1,
      },
    );
    // response.data ==> Map<String,dynamic> or List<dynamic>
    Map<String, dynamic> data = response.data;
    print(data);
  } on DioException catch (e) {
    if (e.response != null) {
      // Handle error response
      print('Error 01: ${e.response!.statusCode}: ${e.response!.statusMessage}');
      // e.response.data ==> Map<String,dynamic> or List<dynamic> or String.
      var errorData = e.response!.data;
      print("Error Data: $errorData");
    } else {
      // Handle no response
      print('Error 02: ${e.message}');
    }
  }
}
Output:
{currentPage: 1, elements: 
[{activated: true, email: anonymous1@example.com, enabled: true, fullName: Anonymous 1, id: 10, 
image: {id: 10, ext: png, size: 16805, width: 128, height: 128}, userName: anonymous1}, 
{activated: true, email: anonymous2@example.com, enabled: true, fullName: Anonymous 2, id: 11, 
image: {id: 11, ext: png, size: 7901, width: 128, height: 128}, userName: anonymous2}, 
{activated: true, email: anonymous3@example.com, enabled: true, fullName: Anonymous 3, id: 12, 
image: {id: 12, ext: png, size: 9139, width: 128, height: 128}, userName: anonymous3}], 
pageSize: 10, totalElements: 3, totalPages: 1}
Bạn có thể chạy lại ví dụ trên với một đường dẫn không tồn tại và xem kết quả.
  • path = '/rest/appUsers/search-XX'
Error 01: 400: 
Error Data: {type: about:blank, title: Bad Request, status: 400, detail: Failed to convert 'page' with value: 'search-XX', instance: /rest/appUsers/search-XX}

7. Dio POST

Phương thức post() của lớp Dio được sử dụng để gửi yêu cầu POST đến máy chủ nhằm tạo tài nguyên.
post()
Future<Response<T>> post<T>(
  String path, {
  Object? data,
  Map<String, dynamic>? queryParameters,
  Options? options,
  CancelToken? cancelToken,
  void Function(int, int)? onSendProgress,
  void Function(int, int)? onReceiveProgress,
});
queryParameters
Chỉ định các "Query parameters" (Tham số truy vấn) bao gồm trong URL của yêu cầu.
data
Chỉ định dữ liệu bao gồm trong phần thân của yêu cầu. Kiểu dữ liệu có thể là:
  • String, Map<String,dynamic>, List<dynamic>, FormData, MultipartFile
cancelToken
Một đối tượng được sử dụng để huỷ yêu cầu. Khi yêu cầu bị huỷ CancelTokenException sẽ được ném ra.
final cancelToken = CancelToken();
onSendProgress
Một hàm callback được gọi trong quá trình dữ liệu đang được gửi đi. Hàm này có ích trong trường hợp upload dữ liệu có dung lượng lớn.
typedef ProgressCallback = void Function(int count, int total);
onReceiveProgress
Một hàm callback được gọi trong quá trình dữ liệu đang được tải về. Hàm này có ích trong trường hợp downoad dữ liệu có dung lượng lớn.
typedef ProgressCallback = void Function(int count, int total);

8. Dio POST Example

New fragment 1414264
dio_post_ex.dart
import 'package:dio/dio.dart';
import '_constants.dart';

// Create a Dio object with Base Options :
final dio = Dio(
  BaseOptions(
    // Please download and Install CrudDemoServer.
    baseUrl: 'http://localhost:8080',
    connectTimeout: Duration(seconds: 5),
    receiveTimeout: Duration(seconds: 5),
    headers: {
      'Accept': 'application/json',
    },
  ),
);

Future<void> main() async {
  Map<String, dynamic> headers = {
    'Authorization': 'Basic $accessToken', // <-----
  };
  //
  Map<String, dynamic> mapData = {
    "name": "Test Product",
    "active": true,
    "price": 20,
    "estimatedInputPrice": 18,
    "taxRate": 0.1,
    "categoryId": 1,
  };
  var formData = FormData.fromMap(mapData);
  //
  try {
    final response = await dio.post(
      '/rest/product/create',
      options: Options(headers: headers),
      data: formData, // FormData
    );
    // response.data ==> Map<String,dynamic> or List<dynamic>
    Map<String, dynamic> data = response.data;
    print(data);
  } on DioException catch (e) {
    if (e.response != null) {
      // Handle error response
      print(
          'Error 01: ${e.response!.statusCode}: ${e.response!.statusMessage}');
      // e.response.data ==> Map<String,dynamic> or List<dynamic> or String.
      var errorData = e.response!.data;
      print("Error Data: $errorData");
    } else {
      // Handle no response
      print('Error 02: ${e.message}');
    }
  }
}
Output:
{active: true, category: {id: 1, name: Alcoholic drink}, 
estimatedInputPrice: 18, id: 19, imageSize: 0, 
name: Test Product, price: 20, taxRate: 0.1}
  • Flutter upload ảnh sử dụng Dio và ImagePicker
Gửi yêu cầu POST với file đính kèm:
Map<String, dynamic> mapData = {
  "name": "Test Product",
  "active": true,
  "price": 20,
  "estimatedInputPrice": 18,
  "taxRate": 0.1,
  "categoryId": 1,
  "imageFileUpload": await MultipartFile.fromFile(
    '/path/to/product.jpg',
    filename: 'product.jpg',
  ),
};
var formData = FormData.fromMap(mapData);

9. Dio PUT

Phương thức put() của lớp Dio được sử dụng để gửi một yêu cầu PUT tới máy chủ để cập nhập một tài nguyên nào đó.
put()
Future<Response<T>> put<T>(
  String path, {
  Object? data,
  Map<String, dynamic>? queryParameters,
  Options? options,
  CancelToken? cancelToken,
  void Function(int, int)? onSendProgress,
  void Function(int, int)? onReceiveProgress,
});
queryParameters
Chỉ định các "Query parameters" (Tham số truy vấn) bao gồm trong URL của yêu cầu.
data
Chỉ định dữ liệu bao gồm trong phần thân của yêu cầu. Kiểu dữ liệu có thể là:
  • String, Map<String,dynamic>, List<dynamic>, FormData, MultipartFile
cancelToken
Một đối tượng được sử dụng để huỷ yêu cầu. Khi yêu cầu bị huỷ CancelTokenException sẽ được ném ra.
final cancelToken = CancelToken();
onSendProgress
Một hàm callback được gọi trong quá trình dữ liệu đang được gửi đi. Hàm này có ích trong trường hợp upload dữ liệu có dung lượng lớn.
typedef ProgressCallback = void Function(int count, int total);
onReceiveProgress
Một hàm callback được gọi trong quá trình dữ liệu đang được tải về. Hàm này có ích trong trường hợp downoad dữ liệu có dung lượng lớn.
typedef ProgressCallback = void Function(int count, int total);

10. Dio PUT Example

dio_put_ex1.dart
import 'package:dio/dio.dart';
import '_constants.dart';

// Create a Dio object with Base Options :
final dio = Dio(
  BaseOptions(
    // Please download and Install CrudDemoServer.
    baseUrl: 'http://localhost:8080',
    connectTimeout: Duration(seconds: 5),
    receiveTimeout: Duration(seconds: 5),
    headers: {
      'Accept': 'application/json',
    },
  ),
);

Future<void> main() async {
  Map<String, dynamic> headers = {
    'Authorization': 'Basic $accessToken', // <-----
  };
  //
  Map<String, dynamic> mapData = {
    "id": 1,
    "name": "333 Beer (Update)", // <== Update Name.
    "active": true,
    "price": 1,
    "estimatedInputPrice": 0.8,
    "taxRate": 0.1,
    "categoryId": 1,
  };
  var formData = FormData.fromMap(mapData);
  //
  try {
    final response = await dio.put(
      '/rest/product/update',
      options: Options(headers: headers),
      data: formData, // FormData
    );
    // response.data ==> Map<String,dynamic> or List<dynamic>
    Map<String, dynamic> data = response.data;
    print(data);
  } on DioException catch (e) {
    if (e.response != null) {
      // Handle error response
      print(
          'Error 01: ${e.response!.statusCode}: ${e.response!.statusMessage}');
      // e.response.data ==> Map<String,dynamic> or List<dynamic> or String.
      var errorData = e.response!.data;
      print("Error Data: $errorData");
    } else {
      // Handle no response
      print('Error 02: ${e.message}');
    }
  }
}
  • Flutter upload ảnh sử dụng Dio và ImagePicker
Gửi yêu cầu PUT với file đính kèm:
Map<String, dynamic> mapData = {
  "id": 1.toString(),
  "name": "333 Beer (Update)", // <== Update Name.
  "active": true,
  "price": 1,
  "estimatedInputPrice": 0.8,
  "taxRate": 0.1,
  "categoryId": 1,
  "imageFileUpload": await MultipartFile.fromFile(
    '/path/to/product.jpg',
    filename: 'product.jpg',
  ),
};
var formData = FormData.fromMap(mapData);

11. Dio DELETE

Phương thức delete() của lớp Dio được sử dụng để gửi một yêu cầu DELETE tới máy chủ để xoá các tài nguyên nào đó.
delete()
Future<Response<T>> delete<T>(
  String path, {
  Object? data,
  Map<String, dynamic>? queryParameters,
  Options? options,
  CancelToken? cancelToken,
});
queryParameters
Chỉ định các "Query parameters" (Tham số truy vấn) bao gồm trong URL của yêu cầu.
cancelToken
Một đối tượng được sử dụng để huỷ yêu cầu. Khi yêu cầu bị huỷ CancelTokenException sẽ được ném ra.
final cancelToken = CancelToken();
data
Chỉ định dữ liệu bao gồm trong phần thân của yêu cầu. Kiểu dữ liệu có thể là:
  • String, Map<String,dynamic>, List<dynamic>, FormData, MultipartFile

12. Dio DELETE Example

dio_delete_ex1.dart
import 'package:dio/dio.dart';
import '_constants.dart';

// Create a Dio object with Base Options :
final dio = Dio(
  BaseOptions(
    // Please download and Install CrudDemoServer.
    baseUrl: 'http://localhost:8080',
    connectTimeout: Duration(seconds: 5),
    receiveTimeout: Duration(seconds: 5),
    headers: {
      'Accept': 'application/json',
    },
  ),
);

Future<void> main() async {
  Map<String, dynamic> headers = {
    'Authorization': 'Basic $accessToken', // <-----
  };
  //
  try {
    final response = await dio.delete(
      '/rest/product/delete/19',
      options: Options(headers: headers),
    );
    print("Done");
  } on DioException catch (e) {
    if (e.response != null) {
      // Handle error response
      print('Error: ${e.response!.statusCode}: ${e.response!.statusMessage}');
      // e.response.data ==> Map<String,dynamic> or List<dynamic> or String.
      var errorData = e.response!.data;
      print("Error Data: $errorData");
    } else {
      // Handle no response
      print('No Response Error: ${e.message}');
    }
  }
} 

13. Các bài viết liên quan

  • Dart Dio Interceptors