728x90
반응형
1. 선택 기준
1) 성능
- 두 라이브러리 모두 Dart의 HttpClient를 기반으로 하며, 실제 요청 속도는 거의 차이가 없습니다.
2) 패키지 크기
- http 패키지는 약 60KB 크기의 .dex 파일을 포함합니다.
- Dio는 기능이 풍부한 만큼, 3.2MB의 핵심 엔진 + 1.25MB의 프레임워크 코드를 포함하여 전체 앱 크기를 많이 증가시킵니다.
3) 대용량 파일 처리
- http는 대용량 파일 다운로드 시 메모리 오버플로우 문제가 발생하기 쉽습니다.
- Dio는 스트리밍 다운로드, 파일 분할 업로드, 중단 후 이어받기 등을 지원하여 메모리 문제를 회피할 수 있습니다.
4) Header 설정의 유연성
- http는 전역 설정 재사용 메커니즘이 없기 때문에, 매 요청마다 Header를 직접 설정해야 합니다.
→ 이를 간소화하려면 자체 http 도구 클래스를 감싸서 사용하는 것이 좋습니다. - Dio는 BaseOptions를 통해 공통 Header를 설정할 수 있고, 모든 요청에서 재사용됩니다.
또한 개별 요청에서는 Options를 사용해 전역 설정을 덮어쓸 수 있어 유연성도 높습니다.
5) 파라미터 전달 복잡도
- 두 라이브러리 모두 큰 차이는 없습니다.
6) 로그 출력
- http는 로그를 수동으로 출력해야 합니다.
- Dio는 LogInterceptor 또는 PrettyDioLogger를 통해
자동으로 포맷된 로그를 출력할 수 있으며,
요청/응답 정보, 소요 시간 등을 출력하고 프록시 설정도 지원하여 패킷 캡처 및 디버깅에 유리합니다.
7) 2차 포장
- 두 라이브러리 모두 싱글톤 패턴 등으로 baseUrl, Header, 파라미터 등을 공통 처리하는 방식으로
2차 포장이 가능합니다.
2. 기본 사용 비교
1) GET 요청
final extraHeaders = {'test': '111'}; // 사용자 정의 Header
final queryParams = {'page': '1', 'per_page': '10'}; // 요청 파라미터
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); // 데이터 변환
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; // 자동 파싱
print('DioResponse: id=${dataList[1]["id"]}');
} else {
print('DioResponse-error');
}
Dio의 responseType 설정:
- ResponseType.json: 기본값, 응답을 자동으로 Map 또는 List로 파싱
- ResponseType.plain: 문자열(String) 형태로 원문 반환
- ResponseType.stream: 스트림(Stream) 형태로 반환
- ResponseType.bytes: 바이트 배열(Uint8List)로 반환
2) POST 요청
final extraHeaders = {
'Authorization': 'Bearer ghp_xxxxxx',
'Accept': 'application/vnd.github.v3+json',
};
const urlRepo = "https://api.github.com/repos/{user}/{repo}/issues";
final url = Uri.parse(urlRepo);
final body = {
'title': 'testIssues',
'body': '상세 재현 단계...',
'labels': ['test', 'issues'],
};
// [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, // 원문 반환
),
);
print('response: ${responseDio.statusCode}');
if (responseDio.statusCode == 200 || responseDio.statusCode == 201) {
print('DioResponse: ${responseDio.data}');
} else {
print('DioResponse-error');
}
3) 파일 업로드
final extraHeaders = {
'Authorization': 'Bearer ghp_xxxxxx',
'Accept': 'application/vnd.github.v3+json',
};
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,
};
// [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,
),
);
print('DioResponse: ${responseDio.statusCode}');
if (responseDio.statusCode == 200 || responseDio.statusCode == 201) {
print('DioResponse: ${responseDio.data}');
} else {
print('DioResponse-error');
}
4) 파일 다운로드 + 진행률 표시
var urlRepo = "https://file.dircleaner.com/apk/dircleaner_2.1.3.apk";
final saveDir = await getExternalStorageDirectory();
final saveFile = File('${saveDir?.path}/test.apk');
print('다운로드 시작: $urlRepo');
// [http]
final client = http.Client();
final request = http.Request('GET', Uri.parse(urlRepo));
final response = await client.send(request);
final totalBytes = response.contentLength ?? 0;
int receivedBytes = 0;
final sink = saveFile.openWrite();
response.stream.listen(
(chunk) {
receivedBytes += chunk.length;
print('진행률: $receivedBytes/$totalBytes -> ${saveFile.path}');
sink.add(chunk);
},
onDone: () {
sink.close();
client.close();
print('다운로드 완료: ${saveFile.path}');
},
onError: (e) {
client.close();
print('다운로드 실패: $e');
},
);
// [Dio]
try {
await Dio().download(
urlRepo,
saveFile.path,
onReceiveProgress: (received, total) {
print('Dio 다운로드 진행률: $received/$total -> ${saveFile.path}');
},
options: Options(
headers: {'User-Agent': 'Flutter-App'}, // 일부 서버는 UA 필요
receiveTimeout: const Duration(minutes: 5), // 대용량 다운로드는 타임아웃 연장 필요
),
);
print('Dio 다운로드 완료: $saveFile');
} on DioException catch (e) {
print('Dio 다운로드 실패: $e');
}
728x90
반응형
'개발 언어 > Flutter' 카테고리의 다른 글
Flutter GUI 개발: 고급 레이아웃과 상태 관리 (5) | 2025.06.16 |
---|---|
Flutter GUI 개발: 애니메이션과 고급 UI 기법 (7) | 2025.06.15 |
Flutter GUI 개발 기초 : Flutter GUI 개발 시작하기 (6) | 2025.06.13 |