[Flutter] Dio 패키지를 통한 http 통신
A powerful HTTP networking package for Dart/Flutter, supports Global configuration, Interceptors, FormData, Request cancellation, File uploading/downloading, Timeout, Custom adapters, Transformers, etc.
Dio는 Flutter/Dart 애플리케이션 개발에서 사용할 수 있는 강력하고 유연한 HTTP 클라이언트 라이브러리이다. 플러터의 대표적 api 통신 라이브버리인 http
보다 더 많은 기능(파일 업로드/다운로드, 인터셉터 등)을 제공하여, 개발자가 복잡한 네트워크 요청과 응답을 쉽게 처리할 수 있도록 도와준다.
사용은 이런 식으로 매우 간단하다!
import 'package:dio/dio.dart';
final dio = Dio();
void getHttp() async {
final response = await dio.get('https://dart.dev');
print(response);
}
Dio의 주요 특징
강력한 요청 처리 기능: Dio는 GET, POST, DELETE, PUT 등 모든 유형의 HTTP 요청을 지원한다. 또한, FormData를 사용한 파일 업로드와 다운로드, 스트림을 통한 대용량 파일 처리 등 복잡한 네트워크 작업을 쉽게 처리할 수 있다.
인터셉터: 요청 및 응답 인터셉터를 사용하여 네트워크 요청과 응답을 가로챌 수 있다. 이를 통해 모든 요청에 공통 헤더를 추가하거나 응답 데이터를 전처리하는 등의 작업을 수행할 있다고 한다.
요청 취소: Dio는 요청 취소 기능을 제공하여, 더 이상 필요하지 않은 HTTP 요청을 취소할 수 있다. 이는 특히 사용자 인터페이스와 상호 작용하는 동안 유용하게 사용될 수 있다.
풍부한 구성 옵션: Dio는 타임아웃 설정, 커스텀 쿠키/헤더 관리, SSL 인증서 검증 등 다양한 구성 옵션을 제공한다. 이를 통해 애플리케이션의 보안 및 네트워크 요구 사항을 충족시킬 수 있다.
오류 처리: Dio는 오류 발생 시 상세한 정보를 제공하며, 다양한 HTTP 오류 상태를 쉽게 처리할 수 있도록 한다.
확실히 http보다는 훨씬 풍부한 기능이 있는 것 같지만, 이번 글에서는 Dio를 활용한 기본적인 http 통신 위주로만 정리해보고자 한다.
HTTP 통신
GET
final dio = Dio();
void request() async {
Response response;
response = await dio.get(
'/test',
queryParameters: {'id': 12, 'name': 'dio'},
);
// 위와 동일: response = await dio.get('/test?id=12&name=dio');
print(response.data.toString());
}
POST
response = await dio.post('/test', data: {'id': 12, 'name': 'dio'});
PUT
response = await dio.put('/test', data: {'id': 12, 'name': 'dio'});
DELETE
response = await dio.delete('/test', data: {'id': 12});
이외 유용한 기능 (일부)
동시에 다중 요청 수행
response = await Future.wait([dio.post('/info'), dio.get('/token')]);
파일 다운로드
response = await dio.download(
'https://pub.dev/',
(await getTemporaryDirectory()).path + '/pub.html',
);
FormData 전송 (여러개의 파일 전송도 가능)
final formData = FormData.fromMap({
'name': 'dio',
'date': DateTime.now().toIso8601String(),
});
final response = await dio.post('/info', data: formData);
Options
options
는 Dio를 사용하여 네트워크 요청을 수행할 때 다양한 HTTP 설정을 구성하는 데 사용된다. 각각의 Dio 요청은 기본적으로 Dio 인스턴스의 기본 설정을 상속받지만, Options
객체를 통해 특정 요청에 대한 구성을 오버라이딩을 통해 커스터마이징할 수 있는 것이다. Options
클래스를 통해 요청의 헤더, 메소드, 타임아웃, 콘텐츠 유형 등을 세밀하게 조정할 수 있고, 이를 통해 요청마다 다른 매개변수를 쉽게 지정할 수 있다.
/// The HTTP request method.
String method;
/// Timeout when sending data.
///
/// Throws the [DioException] with
/// [DioExceptionType.sendTimeout] type when timed out.
///
/// `null` or `Duration.zero` means no timeout limit.
Duration? sendTimeout;
/// Timeout when receiving data.
///
/// The timeout represents:
/// - a timeout before the connection is established
/// and the first received response bytes.
/// - the duration during data transfer of each byte event,
/// rather than the total duration of the receiving.
///
/// Throws the [DioException] with
/// [DioExceptionType.receiveTimeout] type when timed out.
///
/// `null` or `Duration.zero` means no timeout limit.
Duration? receiveTimeout;
/// Custom field that you can retrieve it later in [Interceptor],
/// [Transformer] and the [Response.requestOptions] object.
Map<String, dynamic>? extra;
/// HTTP request headers.
///
/// The keys of the header are case-insensitive,
/// e.g.: `content-type` and `Content-Type` will be treated as the same key.
Map<String, dynamic>? headers;
/// Whether the case of header keys should be preserved.
///
/// Defaults to false.
///
/// This option WILL NOT take effect on these circumstances:
/// - XHR ([HttpRequest]) does not support handling this explicitly.
/// - The HTTP/2 standard only supports lowercase header keys.
bool? preserveHeaderCase;
/// The type of data that [Dio] handles with options.
///
/// The default value is [ResponseType.json].
/// [Dio] will parse response string to JSON object automatically
/// when the content-type of response is [Headers.jsonContentType].
///
/// See also:
/// - `plain` if you want to receive the data as `String`.
/// - `bytes` if you want to receive the data as the complete bytes.
/// - `stream` if you want to receive the data as streamed binary bytes.
ResponseType? responseType;
/// The request content-type.
///
/// The default `content-type` for requests will be implied by the
/// [ImplyContentTypeInterceptor] according to the type of the request payload.
/// The interceptor can be removed by
/// [Interceptors.removeImplyContentTypeInterceptor].
String? contentType;
/// Defines whether the request is considered to be successful
/// with the given status code.
/// The request will be treated as succeed if the callback returns true.
ValidateStatus? validateStatus;
/// Whether to retrieve the data if status code indicates a failed request.
///
/// Defaults to true.
bool? receiveDataWhenStatusError;
/// See [HttpClientRequest.followRedirects].
///
/// Defaults to true.
bool? followRedirects;
/// The maximum number of redirects when [followRedirects] is `true`.
/// [RedirectException] will be thrown if redirects exceeded the limit.
///
/// Defaults to 5.
int? maxRedirects;
/// See [HttpClientRequest.persistentConnection].
///
/// Defaults to true.
bool? persistentConnection;
/// The default request encoder is [Utf8Encoder], you can set custom
/// encoder by this option.
RequestEncoder? requestEncoder;
/// The default response decoder is [Utf8Decoder], you can set custom
/// decoder by this option, it will be used in [Transformer].
ResponseDecoder? responseDecoder;
/// Indicates the format of collection data in request query parameters and
/// `x-www-url-encoded` body data.
///
/// Defaults to [ListFormat.multi].
ListFormat? listFormat;
method: HTTP 요청 메소드를 지정한다 (
GET
,POST
,DELETE
,PUT
등).headers: 요청에 포함될 HTTP 헤더를 지정한다. 예를 들어, 인증 토큰이나 커스텀 헤더 등을 추가할 수 있다.
contentType: 요청의 Content-Type을 설정한다.
application/json
,multipart/form-data
등이 여기에 해당된다.responseType: 응답 데이터의 타입을 지정한다 (
ResponseType.json
,ResponseType.plain
,ResponseType.bytes
등). 이는 Dio가 서버로부터 받은 응답을 어떻게 처리할지 결정한다.followRedirects: 리디렉션을 자동으로 따를지 여부를 결정한다. 기본값은
true
.validateStatus: HTTP 상태 코드가 성공으로 간주되는 조건을 정의한다. 기본적으로 상태 코드가 200에서 299 사이일 때 성공으로 간주된다.
receiveDataWhenStatusError: 상태 코드가 에러 범위에 있을 때도 응답 본문을 받을지 여부를 결정한다.
connectTimeout, sendTimeout, receiveTimeout: 각각 연결 시간 초과, 데이터 전송 시간 초과, 데이터 수신 시간 초과에 대한 타임아웃을 설정한다.
사용 예시:
GET
요청을 보내면서 'Authorization' 헤더를 설정하고, 응답 유형으로 JSON을 지정해보자!
void main() async {
var dio = Dio();
var response = await dio.get(
'https://example.com',
options: Options(
headers: {
'Authorization': 'Bearer your_token',
},
responseType: ResponseType.json,
),
);
print(response.data);
}
Interceptors
Dio의 Interceptors
는 HTTP 요청/응답 프로세스에 훅(Hook)을 추가하여 요청이 실행되기 전, 실행 도중, 그리고 응답을 받은 후에 사용자 정의 로직을 실행할 수 있게 해주는 강력한 기능이다. 이를 통해 개발자는 네트워크 요청의 로깅, 인증 토큰 추가, 에러 처리, 응답 데이터 전처리 등 다양한 공통 작업을 중앙에서 관리할 수 있다.
Dio에서 인터셉터를 추가하려면 'Dio' 객체의 'interceptors' 속성에 인터셉터를 추가하면 된다. 'interceptors' 속성은 'Interceptor' 객체의 리스트를 가지며, 각 인터셉터는 'onRequest', 'onResponse', 'onError' 콜백을 구현 가능하다.
공식 문서에 다양한 예시가 나와있으니 인터셉터 기능이 필요할 때는 공식 문서를 꼭! 참고해보도록 하자.
사용 예시:
void main() {
var dio = Dio();
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 요청이 실행되기 전에 로직을 실행
print('Sending request to ${options.uri}');
// 요청을 계속 진행하려면 다음 핸들러를 호출해야 함.
handler.next(options);
},
onResponse: (response, handler) {
// 응답을 받은 후의 로직을 실행
print('Received response from ${response.requestOptions.uri}');
// 응답을 계속 진행하려면 다음 핸들러를 호출해야 함.
handler.next(response);
},
onError: (DioError e, handler) {
// 에러가 발생했을 때의 로직을 실행
print('Request failed: ${e.message}');
// 에러를 계속 진행하려면 다음 핸들러를 호출해야 함.
handler.next(e);
},
));
// 이제 모든 요청, 응답, 에러는 위에 정의한 인터셉터를 통과한다!
}
ref
Subscribe to my newsletter
Read articles from Cherrie Kim directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by