Dio 패키지로 api 통신을 하는데,
retrofit 패키지로 반복적인 api 요청, 응답 후 매핑 로직자체를 자동으로 생성하게 만들고, 여기서 accessToken 을 헤더에 담아야 하는데,
Interceptor 로 가로채서 accessToken 이 유효한지 체크해보는 시간을 갖겠다.
말 그대로 가로챈다~
새로 앱을 시작하면, accessToken 과 refreshToken 을 발급을 받았다.
accessToken 이 만료가 되었을때, refreshToken 을 이용해서 accessToken 을 새로 발급 받아와 flutter securestorage 에 저장하는 법을 안배웠다.
Interceptor 를 상속을 받으면, onRequest, onResponse, onError 함수를 호출할 수 있다.
그래서 api 통신을 해보면 요청 보낼때 pirnt 가 잘 출력되는 것을 볼 수 있다.
import 'package:dio/dio.dart';
class CustomInterceptor extends Interceptor {
// 1) 요청 보낼때
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
print('[REQ] [${options.method}] ${options.uri}');
return super.onRequest(options, handler);
}
// 2) 응답을 받을때
void onResponse(Response response, ResponseInterceptorHandler handler) {
// TODO: implement onResponse
return super.onResponse(response, handler);
}
// 3) 에러가 났을때
void onError(DioError err, ErrorInterceptorHandler handler) {
// TODO: implement onError
return super.onError(err, handler);
}
}
final dio = Dio();
// 추가
dio.interceptors.add(
CustomInterceptor();
)
스토리지안에서 토큰을 가져오기 위해서 선언
Interceptor 를 해서 401 status 에러가 나는 것을 감지해서 토큰을 새로 발급받는
401 에러는 accessToken 이 만료될 때 나오는 에러이다.
void onError(DioError err, ErrorInterceptorHandler handler) async {
// 401 에러가 날때 (status code)
// 토큰을 재발급 받는 시도를 한다.
// 토큰이 재발급되면, 다시 새로운 토큰으로 요청을 한다.
print('[ERR] [${err.requestOptions.method}] ${err.requestOptions.uri}');
final refreshToken = await storage.read(key: REFRESH_TOKEN_KEY);
// refreshToken 이 없으면
// 당연히 에러를 던진다.
if (refreshToken == null) {
// 에러를 던질때는 handler.reject 를 사용한다.
return handler.reject(err);
}
final isStatus401 = err.response?.statusCode == 401;
final isPathRefresh = err.requestOptions.path == '/auth/token';
if (isStatus401 && !isPathRefresh) {
final dio = Dio();
try {
final res = await dio.post(
'http://$ip/auth/token',
options: Options(headers: {
'authorization': 'Bearer $refreshToken',
}),
);
final accessToken = res.data['accessToken'];
final options = err.requestOptions;
// 토큰 변경하기
options.headers.addAll({
'authorization': 'Bearer $accessToken',
});
await storage.write(key: ACCESS_TOKEN_KEY, value: accessToken);
// 요청 재전송
final response = await dio.fetch(options);
return handler.resolve(response);
} on DioError catch (e) {
// on DioError : 오직 DioError 만!
return handler.reject(e);
}
}
return handler.reject(err);
}
응답 받을때는 딱히 컨트롤 할게 없기 때문에, print문만 출력했다.
void onResponse(Response response, ResponseInterceptorHandler handler) {
print('[RES] [${response.requestOptions.method}] ${response.requestOptions.uri}');
return super.onResponse(response, handler);
}
도움이 많이 됐습니다 감사합니다!