auth 관련 에러
198
작성한 질문수 2
7강 마지막 들으면서 적용하는데
분명 에뮬레이터도 정상동작인데 dio.dart의 onError함수에서 계속 401 auth에러가 발생한다고 표시가 돼서 콘솔로 디버깅을 했습니다.
그런데 마지막 resending하는 부분까지 정상 도달은 하지만 onResponse의 콘솔은 뜨지않고 재시작해서 accessToken을 다시 발급 받았음에도 계속 onError에서 401auth 에러가 발생합니다. 어떤 부분이 문제일까요
[요약]
토큰만료 =>홈 스크린에 데이터 사라짐 => 재시작 => 홈 스크린에 데이터 불러와짐 => 문제발생 데이터는 불러와지는데 디버그 콘솔에 REQ랑 ERROR표시남(401 AUTH 관련 에러) => 재시작 => 동일 에러 무한
[에러 내용]
I/flutter ( 4232): [REQ] [GET] http://10.0.2.2:3000/restaurant/
I/flutter ( 4232): [ERROR] [GET] http://10.0.2.2:3000/restaurant/
I/flutter ( 4232): [ERROR] [MESSAGE] This exception was thrown because the response has a status code of 401 and RequestOptions.validateStatus was configured to throw for this status code.
I/flutter ( 4232): The status code of 401 has the following meaning: "Client error - the request contains bad syntax or cannot be fulfilled"
I/flutter ( 4232): Read more about status codes at https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
I/flutter ( 4232): In order to resolve this exception you typically have either to verify and fix your request code or you have to fix the server code.
dio.dart
import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:section2/common/const/data.dart';
class CustomInterceptor extends Interceptor {
final FlutterSecureStorage storage;
CustomInterceptor({
required this.storage,
});
/// 1) 요청 보낼 때
/// 요청이 보내질때마다
/// 만약에 요청의 Headers에 accessToken이 true 이면
/// 실제 토큰을 가져와서 기존 accessToken값을 삭제하고 {
/// authorization : Beader $토큰} 값을 추가
@override
void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
print('[REQ] [${options.method}] ${options.uri}');
if (options.headers['accessToken'] == 'true') {
options.headers.remove('accessToken');
final accessToken = await storage.read(key: ACCESS_TOKEN_KEY);
options.headers.addAll(
{'authorization': 'Bearer $accessToken'},
);
}
if (options.headers['refreshToken'] == 'true') {
options.headers.remove('refreshToken');
final refreshToken = await storage.read(key: REFRESH_TOKEN_KEY);
options.headers.addAll(
{'authorization': 'Bearer $refreshToken'},
);
}
return super.onRequest(options, handler);
}
/// 2) 응답 받을 때
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
print(
'[RES] [${response.requestOptions.method}] ${response.requestOptions.uri}');
super.onResponse(response, handler);
}
/// 3) 에러 났을 때
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
// 401에러 났을 때 (status code)
// 토큰을 재발급 받는 시도를하고 토큰이 재발급되면
// 다시 새로운 토큰을 요청한다.
print('[ERROR] [${err.requestOptions.method}] ${err.requestOptions.uri}');
print('[ERROR] [MESSAGE] ${err.message}');
// refreshToken이 없는 경우
final refreshToken = await storage.read(key: REFRESH_TOKEN_KEY);
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);
// 에러난 요청options에 토큰값을 신규로 변경하여 재전송
final resending = await dio.fetch(options);
return handler.resolve(resending);
} on DioException catch (e) {
return handler.reject(e);
}
}
return handler.reject(err);
}
}


답변 3
0
안녕하세요!
남겨주신 깃허브 살펴봤습니다.
너무 아쉬운 에러인데 바로 들으시겠습니까? 아니면 직접 한번 더 찾아보시겠습니까?
감사합니다!
0
어제는 제가 늪에 빠진거같아요.. 항상 개발하면서 느끼는거지만 에러가 발생 했을 때 침착하게 돌면 찾을수 있는거를 급해지면서 참,,,댓글 보고 한번 더 순차적으로 돌았는데 발견했습니다 감사합니다.
0
안녕하세요, 인프런 AI 인턴입니다. dev님!
401 에러는 보통 인증에 관련된 문제입니다. 현재 여러분의 상황을 요약하자면, 토큰이 만료되어 재발급을 받고 다시 시도하는 중에도 여전히 401 오류가 발생하는 것입니다. 이 문제의 원인은 여러 가지가 있을 수 있습니다. 아래에서 몇 가지 가능한 해결책을 제시합니다.
토큰 저장과 로딩 확인: 새로운 accessToken을 제대로 저장하고 있는지 확인하세요.
storage.write(key: ACCESS_TOKEN_KEY, value: accessToken);이 부분이 성공적으로 작동하는지 디버깅으로 로그를 추가하여 확인해보세요. 또한, 토큰이 저장될 때나 읽어들일 때 올바른 키를 사용하고 있는지 확인하세요.재시도 로직 확인: 에러가 발생했을 때 재시도하는 로직이 올바르게 작동하는지 확인합니다.
options.headers.addAll({'authorization': 'Bearer $accessToken'});이 부분에서 새로운 토큰을 제대로 추가했는지 확인하고,dio.fetch(options);를 통해 위의options객체가 정확하게 설정되어 있는지 확인해야 합니다.서버 응답 확인: 서버 측에서 실제로 반환하는 에러 메시지를 살펴보세요. 401 에러가 발생하면 서버 로그에서도 해당 요청에 대해 무엇이 잘못되었는지 명확하게 보여줄 수 있습니다. 이는 서버 코드에서 발행되는 특정 상호 작용이나 잘못 설정된 토큰 정보일 수 있습니다.
디버그 로그 추가: 응답을 다시 시도하기 전과 후에 로그를 남겨, 어떤 과정에서 무엇이 잘못되는지 보다 명백하게 확인할 수 있습니다. 추가적인 디버깅 로그를 통해 문제가 발생하는 단계나 코드를 명확히 알 수 있습니다.
다음 링크도 참고해보시면 도움이 될 수 있습니다:
이외에도 상당수의 강의 참여자들이 유사한 문제를 겪고 해결한 사례를 볼 수 있으니, 비슷한 상황을 검색하시거나 관련 포스팅을 확인해보시는 것도 좋습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
Isar 마지막 업데이트는 2년전입니다.
0
30
0
FlutterSecureStorage 질문
0
31
0
Dio onError Interceptor 만드는 부분에 질문이 있습니다.
0
79
2
관리자 기능에 대한 질문
0
100
2
part 'restaurant_model.g.dart';
0
92
1
36강. dio 인터셉터에 storage를 전달하는 코드가 이해 안되는데요. 도움 부탁드립니다.
0
56
2
2번 반환 상황 관련 질문
0
61
2
riverpod 3.0
0
139
2
Asset folder??
0
82
2
디자이너와 협업 시 프레임 크기 설정 관련 질문
0
113
2
FutureProvider, StateNotifierProvider 선택 기준
0
70
2
컴포넌트 모델화
0
64
2
쿼리 파라미터
0
84
2
화면 안보임
0
67
2
PaginationListView
0
54
1
강의중 37.Dio onErrorInterceptor 작업하기 dio 관련 질문입니다.
0
101
2
프로토타입이미지
0
62
2
여러 객체를 상태 관리하는 방법에 대한 질문
0
84
2
장바구니 결제하기 응답이 500이 옵니다.
0
105
2
removeFromBasket에서 await patchBasket()을 마지막에 하면 에러나는거 아닌가요?
0
67
2
이 두가지는 완전히 동일한 기능인가요?
0
106
3
내부 코드를 작성하지 않은 CursorPaginationLoading가 어떻게 로딩상태를 갖는지 잘 모르겠습니다...
0
77
2
_SplashScreenState에서 storage를 late로 호출해서 한번만 불러와도 되나요?
0
86
2
코딩 작성 순서 관련 질문
0
88
2





