Dio란?
(A powerful http client for dart)
http 라이브러리 처럼 서버와 통신을 하기 위해 필요한 패키지. http와 다르게 사용하기 쉽게 보다 많은 기능들을 제공하고 있으며 커스텀을 통해 사용하기 편하다.
- Rest API 통신에 가장 인기 많은 라이브러리
- http와 다르게 응답 받은 JSON 파일을 dart:convert를 통해 디코딩 할 필요 없이 디코딩된 상태로 리턴된다
- options, interceptor를 통해 다양한 기능을 한 번에 핸들링 할 수 있다
설정
// pubspec.yaml
dependencies:
dio: ^5.3.3
주요 기능
// 기초
Dio _dio = Dio();
// 첫번째
final response = await _dio.get('/test?id=1&name=voyage');
// 두번째
final response = await _dio.get('/test', queryParameters: {'id': 1, 'name': 'voyage'});
// 세번째
final response = await _dio.request(
'/test',
data: {'id':1,'name':'xx'},
options: Options(method:'GET'),
);
// post 첫번째
final response = await _dio.post('/test', data: {'id': 1, 'name': 'voyage'});
// post 두번째
Map<String, dynamic> _data = {
"test" : 1,
"test2" : 2,
};
await _dio.post($url,data:_data);
// put
Map<String, dynamic> _data = {
"test" : 1,
"test2" : 2,
};
await _dio.put($url,data:_data);
// delete
Map<String, dynamic> _data = {
"test" : 1,
"test2" : 2,
};
await _dio.delete($url,data:_data);
- axios와 비슷하게 각 메서드 별로 함께 넘길 수 있는 여러가지 파라미터들이 있다. (쿼리 + body)
dioService.dart
class DioServices {
static final DioServices _dioServices = DioServices._internal();
factory DioServices() => _dioServices;
Map<string, dynamic=""> dioInformation = {};
static Dio _dio = Dio();
DioServices._internal() {
BaseOptions _options = BaseOptions(
baseUrl:'<https://www.xx.com/api>' || $url;,
connectTimeout: const Duration(milliseconds: 10000),
receiveTimeout: const Duration(milliseconds: 10000),
sendTimeout: const Duration(milliseconds: 10000),
// headers: {},
);
_dio = Dio(_options);
_dio.interceptors.add(DioInterceptor());
}
Dio to() {
return _dio;
}
}
</string,>
Dio를 싱클톤으로 즉, 인스턴스를 제한하여 기존 인스턴스를 리턴하고 하나의 인스턴스만 생성되도록 하는 패턴으로 기존 객체를 가져다 사용하는 패턴을 사용한다
BaseOptions에서 사용하는 옵션들은
- baseUrl: 요청할 기본 주소를 설정할 수 있다.
- connectTimeout: 서버로부터 응답받는 시간을 설정할 수 있다.
- receiveTimeout: 파일 다운로드 등과 같이 연결 지속 시간을 설정할 수 있다.
- headers: 요청의 header 데이터를 설정할 수 있다. ex) 인증 토큰
공통적으로 사영되는 것은 dio 생성시 설정, 그 외에 것들은 요청에 맞게 설정하는 식이 좋다.
Dio Interceptor
- Interceptor는 요청 때 마다 가로채는 역할을 한다.
- DioInterceptor 객체를 생성 후 Interceptor 객체를 상속받는다.
- Interceptor 객체에는 onRequest / onResponse / onError 함수를 override 하여 재 정의해서 사용할 수 있다.
- 로그 및 상태 핸들링을 할 수 있다.
- ex) 로그인 토큰이 만료 되었을 때, onError 부분에 401 에러 조건을 추가 후 로그인 페이지로 보내주는 작업
class DioInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
logger.e("BaseUrl ${options.baseUrl}");
logger.e("Path ${options.path}");
logger.e("Parameters ${options.queryParameters}");
logger.e("Data ${options.data}");
logger.e("Connect Timeout ${options.connectTimeout}");
logger.e("Send Timeout ${options.sendTimeout}");
logger.e("Receive Timeout ${options.receiveTimeout}");
super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
logger.e(response.statusCode);
logger.e(response.data);
logger.e("BaseUrl ${response.requestOptions.baseUrl}");
logger.e("Path ${response.requestOptions.path}");
logger.e("Parameters ${response.requestOptions.queryParameters}");
logger.e("Data ${response.requestOptions.data}");
logger.e("Connect Timeout ${response.requestOptions.connectTimeout}");
logger.e("Send Timeout ${response.requestOptions.sendTimeout}");
logger.e("Receive Timeout ${response.requestOptions.receiveTimeout}");
super.onResponse(response, handler);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
logger.e("Error ${err.error}");
logger.e("Error Message ${err.message}");
super.onError(err, handler);
}
}
Dio _dio = DioServices().to();
await _dio.get("요청URL");
Interceptors Lock / unlock
dio.interceptors.add(InterceptorsWrapper(
onRequest: (Options options, handler) async {
print('send request:path:${options.path},baseURL:${options.baseUrl}');
if (csrfToken == null) {
print('no token,request token firstly...');
//lock the dio.
dio.lock();
tokenDio.get('/token').then((d) {
options.headers['csrfToken'] = csrfToken = d.data['data']['token'];
print('request token succeed, value: ' + d.data['data']['token']);
print( 'continue to perform request:path:${options.path},baseURL:${options.path}');
handler.next(options);
}).catchError((error, stackTrace) {
handler.reject(error, true);
}) .whenComplete(() => dio.unlock()); // unlock the dio
} else {
options.headers['csrfToken'] = csrfToken;
handler.next(options);
}
}
));
- Interceptor를 통해 요청을 lock 혹은 unlock 할 수 있다.
- 위에 코드는 토큰의 유무를 검사 즉, Interceptor를 통해 요청 때 마다 토큰의 유무를 검사하여 만약 토큰이 없다면 새로운 토큰을 요청해서 다시 이후에 요청을 진행한다. 이때 토큰이 없다면 Interceptor를 lock해서 대기열에 넣운 후 토큰을 받은 뒤 다시 unlock하는 역할이다.
출처 : 아래의 사이트들을 보면서 큰 공부 하였습니다
https://velog.io/@leeeeeoy/Flutter-Dio-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC
'Front-End > Flutter' 카테고리의 다른 글
[Flutter] GestureDetector (0) | 2023.10.28 |
---|---|
[Flutter] 내장 Image file (0) | 2023.10.28 |
[Flutter] Navigator (0) | 2023.10.28 |
[Flutter] 앱 통신 방법 및 에러 처리 (0) | 2023.10.28 |
[Angela Yu] Flutter Start (0) | 2023.09.24 |