Dio는 Dart와 Flutter를 위한 강력한 HTTP 클라이언트로, 중국 엔지니어 Wenda Wang이 개발했습니다. 이 라이브러리는 인터셉터, FormData, 파일 업로드 및 요청 취소를 지원하는 고급 API를 제공합니다. pub.dev, 2025에 따르면 Dio는 GitHub에서 8,000개 이상의 스타를 보유한 Flutter 생태계에서 가장 인기 있는 HTTP 클라이언트입니다.
핵심 사항
Dio는 Dart 언어를 위한 강력한 HTTP 클라이언트 라이브러리로, Flutter 애플리케이션에서 가장 널리 사용됩니다. Dio는 인터셉터, 전역 구성, 트랜스포머, FormData, 파일 업로드 및 유연한 타임아웃 관리를 지원하는 풍부한 API를 제공하여 Flutter 커뮤니티에서 네트워킹의 주요 선택이 되고 있습니다.
이 라이브러리는 2018년 Wenda Wang이 최신 기능(모든 요청에 대한 통합 구성, 인터셉터, 자동 직렬화)이 부족했던 내장 dart:io HttpClient의 대안으로 만들었습니다. 2025년까지 Dio는 인기에서 Dart 팀의 http 패키지를 추월하여 pub.dev에 따르면 Flutter 생태계의 HTTP 클라이언트 중 1위를 차지했습니다.
Dio는 세 가지 어댑터를 지원합니다: DartNativeAdapter(Android, iOS, Desktop에서 기본), BrowserAdapter(Web), IOAdapter. 어댑터는 플랫폼에 따라 자동으로 선택됩니다. Dio는 또한 모든 Flutter 플랫폼(Android, iOS, Web, macOS, Windows, Linux)에 통합 인터페이스를 제공합니다.
Dio의 아키텍처는 핸들러 체인으로 구축됩니다. 각 요청은 인터셉터 시퀀스를 통과하며, 요청(InterceptorsWrapper.onRequest), 응답(onResponse)을 수정하거나 오류(onError)를 처리할 수 있습니다. 인터셉터 이후 요청은 트랜스포머(Transformer)로 전달되어 전송 전에 데이터를 변환합니다.
Dio 인스턴스는 기본 URL, 기본 헤더, 타임아웃, 응답 유형(JSON, stream, plain), 쿼리 매개변수 및 데이터 형식을 포함하는 BaseOptions 객체를 통해 구성됩니다. 이러한 설정은 모든 요청에 적용되지만 특정 요청에서 재정의할 수 있습니다. BaseOptions는 애플리케이션 전체에 단일 구성 지점을 제공하여 엔드포인트 변경이나 전역 헤더 추가를 간소화합니다.
Dio의 각 요청은 Response<T>를 반환합니다. 여기서 T는 트랜스포머 처리 후의 데이터 유형입니다. 기본적으로 Dio는 JSON 응답을 Map<String, dynamic>으로 자동 변환합니다. 유형화된 응답의 경우 Dio는 직렬화 패키지(json_serializable, freezed 또는 built_value)와 함께 사용됩니다. Response에는 data, headers, statusCode, requestOptions 및 추가 데이터가 포함됩니다.
기본 구성은 Dio(BaseOptions)를 통해 생성됩니다. 모든 요청에 대한 baseUrl, connectTimeout 및 receiveTimeout, content-type 및 accept 헤더, queryParameters를 설정할 수 있습니다. 이러한 모든 매개변수는 각 요청에 적용되어 코드 중복을 없애고 네트워크 설정 관리를 중앙화합니다.
Dio는 두 가지 직렬화 모드를 지원합니다: 기본 JSON(responseType: ResponseType.json) 및 스트리밍(ResponseType.stream). 스트림 모드에서 Response.data는 청크로 읽을 수 있는 ResponseBody를 반환합니다. 이는 모든 것을 메모리에 로드하는 것이 바람직하지 않은 대용량 페이로드 파일에 편리합니다. 일반 모드는 자동 JSON 파싱 없이 원시 문자열을 반환합니다.
인터셉터는 요청, 응답 및 오류를 가로채고 수정하는 Dio의 핵심 메커니즘입니다. OkHttp의 Interceptor와 Ktor의 플러그인을 완전히 대체하지만 Dart 특화 API와 Future를 통한 비동기 지원을 제공합니다. 인터셉터는 전역 Dio 구성과 개별 요청 모두에 추가할 수 있습니다.
| 인터셉터 메서드 | 목적 | 사용 예 |
|---|---|---|
| onRequest | 전송 전 요청 수정 | 인증 토큰 추가 |
| onResponse | 성공 응답 처리 | 데이터를 DTO 객체로 변환 |
| onError | 요청 오류 처리 | 503 시 자동 재시도 |
내장 LogInterceptor는 각 요청을 기록합니다: 메서드, URL, 헤더, 본문 및 실행 시간. 컴팩트 모드(요청당 한 줄)와 전체 모드(본문 포함 전체 정보)의 두 가지 모드가 있습니다. LogInterceptor는 개발 중에 특히 유용하지만 조건부 import 또는 전역 플래그를 통해 릴리스 빌드에서 비활성화하는 것이 좋습니다.
사용자 정의 인터셉터는 InterceptorsWrapper 클래스를 통해 생성됩니다. 하나, 둘 또는 세 가지 메서드(onRequest, onResponse, onError)를 모두 재정의할 수 있습니다. Dio는 인터셉터가 인터셉터 목록에 추가된 순서대로 엄격하게 실행합니다. 인터셉터가 handler.next()를 호출하지 않으면 체인이 중단되고 응답 또는 오류가 애플리케이션에 도달하지 않습니다.
Dio에서 인증을 위해 Authorization 헤더에 Bearer 토큰을 추가하는 인터셉터를 사용합니다. 서버가 401을 반환하면 onError의 인터셉터가 갱신 요청을 통해 토큰을 새로고침하고 새 토큰으로 원래 요청을 재시도합니다. 이 패턴을 토큰 갱신 인터셉터라고 하며 response?.statusCode == 401을 확인하여 DioException을 통해 구현됩니다.
Dio는 재시도 로직에 대한 내장 지원을 dio_smart_retry 패키지 또는 사용자 정의 RetryInterceptor를 통해 제공합니다. 모바일 애플리케이션에서 재시도는 중요합니다: 연결이 2-3초 동안 끊어지면 Dio는 connectionTimeout 또는 connectionError 유형의 DioException을 throw합니다. RetryInterceptor는 이 예외를 포착하고 지수 백오프(1초, 2초, 4초)로 최대 3회까지 요청을 재시도하여 불안정한 네트워크 환경에서 애플리케이션 안정성을 향상시킵니다.
Dio를 사용한 기본 GET 요청을 살펴보겠습니다. BaseOptions로 인스턴스를 생성하고 기본 URL과 타임아웃을 설정합니다. 요청은 get() 메서드를 통해 실행되며 Map 형식의 데이터가 포함된 Response를 반환합니다.
final dio = Dio(BaseOptions(
baseUrl: 'https://api.github.com',
connectTimeout: Duration(seconds: 15),
receiveTimeout: Duration(seconds: 15),
headers: {
'Accept': 'application/vnd.github.v3+json',
},
))
final response = await dio.get('/users/octocat')
print(response.data['로그인'])
JSON 본문이 있는 POST 요청의 경우 Map 객체 또는 사용자 정의 DTO를 전달합니다. Dio는 jsonEncode를 통해 Map을 자동으로 JSON으로 직렬화합니다. 유형화된 DTO의 경우 queryParameters 옵션, data 필드 또는 사용자 정의 Transformer를 사용합니다.
final data = {
'name': 'my-project',
'description': 'Created via Dio',
'private': false,
}
final response = await dio.post(
'/user/repos',
data: data,
options: Options(
contentType: ContentType.json.value,
),
)
print(response.data['ID'])
사용자 정의 인터셉터는 각 요청에 Bearer 토큰을 추가합니다. onRequest 메서드는 전송 전에 실행되어 헤더를 수정합니다. 401 응답 시 인터셉터는 토큰을 갱신하고 dio.fetch(requestOptions) 메서드를 통해 요청을 재시도할 수 있습니다.
class AuthInterceptor extends InterceptorsWrapper {
final String token
AuthInterceptor(this.token)
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
options.headers['Authorization'] = 'Bearer $token'
handler.next(options)
}
}
dio.interceptors.add(AuthInterceptor('ghp_abc123'))
Dio는 FormData를 통한 파일 업로드를 간소화합니다. 파일을 보내려면 File, Bytes 또는 AssetBundle에서 MultipartFile을 생성합니다. FormData는 올바른 경계와 인코딩으로 multipart/form-data 헤더를 자동으로 설정합니다. Dio는 onSendProgress를 통해 업로드 진행 상황을 지원합니다.
파일 다운로드에는 download() 메서드를 사용하여 데이터 스트림을 파일에 직접 저장합니다. Dio는 Range 헤더를 통해 중단된 다운로드 재개를 지원하며, 특히 대용량 파일에 유용합니다. 다운로드 진행 상황은 onReceiveProgress를 통해 추적되어 UI에 진행 표시줄을 표시할 수 있습니다.
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
'/path/to/photo.jpg',
filename: 'photo.jpg',
),
'description': 'Profile photo',
})
await dio.post(
'/upload',
data: formData,
onSendProgress: (sent, total) {
final progress = sent / total * 100
print('업로드: $progress%')
},
)
// 파일 다운로드
await dio.download(
'https://example.com/file.zip',
'/storage/emulated/0/Download/file.zip',
onReceiveProgress: (received, total) {
print('다운로드: ${received / total * 100}%')
},
)
잘못된 오류 처리가 가장 흔한 문제입니다. Dio는 네트워크 사용 불가, 타임아웃, HTTP 오류 4xx/5xx 등 모든 문제에 대해 DioException(이전 DioError)을 throw합니다. 많은 개발자가 일반 Exception만 포착하여 오류 유형과 이를 구체적으로 처리하는 기능에 대한 정보를 잃습니다. 실패 원인을 확인하려면 DioException.type을 사용하세요.
CancelToken 무시는 요청 누수로 이어집니다. 사용자가 요청이 실행 중인 동안 화면을 나가면 Dio가 리소스를 낭비하고 폐기된 State를 업데이트하려고 시도할 수 있습니다. 각 요청에 대해 항상 CancelToken을 생성하고 dispose()에서 취소하세요. CancelToken은 cancel 유형의 DioException을 생성하며 적절히 처리해야 합니다.
일시적 오류에 대한 재시도 로직 부재. 모바일 기기에서는 네트워크를 짧은 시간 동안 사용할 수 없는 경우가 많습니다. 타임아웃 또는 503/502 응답 시 자동 요청 재시도 인터셉터를 구현하세요. dio_smart_retry 패키지의 RetryInterceptor를 사용하거나 시도 간 지수 백오프가 있는 사용자 정의 인터셉터를 작성하세요.
자주 묻는 질문
Dio는 인터셉터, 전역 BaseOptions 구성, FormData, 업로드 진행 상황 및 CancelToken을 제공합니다. Dart 팀의 http 패키지는 최소한으로 인터셉터나 전역 구성이 없습니다. Dio는 대규모 프로젝트에 사용되고 http는 간단한 스크립트에 사용됩니다.
기본적으로 Dio는 jsonDecode를 사용하여 JSON을 Map으로 변환합니다. 유형화된 직렬화를 위해 json_serializable 또는 freezed 패키지를 사용하세요. onResponse에서 fromJson()을 통해 response.data를 DTO로 변환하는 사용자 정의 인터셉터를 만드세요.
CancelToken을 생성하고 요청 옵션에 전달하세요. token.cancel()을 호출하면 요청이 중단되고 cancel 유형의 DioException이 throw됩니다. CancelToken은 여러 요청을 동시에 취소할 수 있어 화면을 나갈 때 모든 요청을 취소하는 데 편리합니다.
네, Dio는 6가지 Flutter 플랫폼 모두에서 작동합니다: Android, iOS, Web, macOS, Windows, Linux. 각 플랫폼은 적응형 HTTP 클라이언트를 사용합니다: DartNativeAdapter(네이티브 플랫폼) 및 BrowserAdapter(Web). 모든 플랫폼을 위한 통합 API는 Flutter 프로젝트에서 Dio의 주요 장점입니다.
Dio는 쿠키를 자동으로 관리하지 않습니다. 쿠키 지원을 위해 dio_cookie_manager 패키지를 cookie_jar와 함께 사용하세요. CookieManager는 Set-Cookie 및 Cookie 헤더를 가로채고 동일한 도메인에 대한 후속 요청에서 자동 전송을 위해 PersistCookieJar에 쿠키를 저장합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.