134 lines
3.5 KiB
Dart
134 lines
3.5 KiB
Dart
import 'package:dio/dio.dart';
|
|
import 'package:cookie_jar/cookie_jar.dart';
|
|
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
|
|
import 'package:flutter/material.dart';
|
|
import '../config/api_config.dart';
|
|
import '../services/auth_service.dart';
|
|
import '../screens/auth/login_screen.dart';
|
|
import '../main.dart'; // navigatorKey를 사용하기 위한 import
|
|
|
|
class ApiService {
|
|
static final ApiService _instance = ApiService._internal();
|
|
factory ApiService() => _instance;
|
|
|
|
late Dio _dio;
|
|
final CookieJar _cookieJar = CookieJar();
|
|
String? _token;
|
|
|
|
ApiService._internal() {
|
|
_dio = Dio(BaseOptions(
|
|
baseUrl: ApiConfig.baseUrl,
|
|
connectTimeout: const Duration(seconds: 10),
|
|
receiveTimeout: const Duration(seconds: 10),
|
|
contentType: 'application/json',
|
|
));
|
|
|
|
// 쿠키 관리자 설정
|
|
_dio.interceptors.add(CookieManager(_cookieJar));
|
|
|
|
// 로그 인터셉터 (디버깅용)
|
|
_dio.interceptors.add(LogInterceptor(
|
|
requestBody: true,
|
|
responseBody: true,
|
|
));
|
|
}
|
|
|
|
// 토큰 설정
|
|
void setToken(String token) {
|
|
_token = token;
|
|
_dio.options.headers['Authorization'] = 'Bearer $token';
|
|
}
|
|
|
|
// GET 요청
|
|
Future<dynamic> get(String path, {Map<String, dynamic>? queryParameters}) async {
|
|
try {
|
|
final response = await _dio.get(
|
|
path,
|
|
queryParameters: queryParameters,
|
|
);
|
|
return response.data;
|
|
} on DioException catch (e) {
|
|
_handleError(e);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
// POST 요청
|
|
Future<dynamic> post(String path, {dynamic data}) async {
|
|
try {
|
|
final response = await _dio.post(
|
|
path,
|
|
data: data ?? {},
|
|
);
|
|
return response.data;
|
|
} on DioException catch (e) {
|
|
_handleError(e);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
// PUT 요청
|
|
Future<dynamic> put(String path, {dynamic data}) async {
|
|
try {
|
|
final response = await _dio.put(
|
|
path,
|
|
data: data,
|
|
);
|
|
return response.data;
|
|
} on DioException catch (e) {
|
|
_handleError(e);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
// DELETE 요청
|
|
Future<dynamic> delete(String path) async {
|
|
try {
|
|
final response = await _dio.delete(path);
|
|
return response.data;
|
|
} on DioException catch (e) {
|
|
_handleError(e);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
// 에러 처리
|
|
void _handleError(DioException e) {
|
|
if (e.response != null) {
|
|
print('API 에러: ${e.response?.statusCode} - ${e.response?.data}');
|
|
|
|
// 401 오류 (인증 실패) 처리
|
|
if (e.response?.statusCode == 401) {
|
|
print('인증 오류: 토큰이 유효하지 않습니다. 로그아웃 처리합니다.');
|
|
_handleUnauthorized();
|
|
}
|
|
} else {
|
|
print('API 요청 에러: ${e.message}');
|
|
}
|
|
}
|
|
|
|
// 인증 오류 처리 (401)
|
|
void _handleUnauthorized() {
|
|
// 다음 프레임에서 실행하여 현재 API 호출 스택이 완료되도록 함
|
|
Future.microtask(() async {
|
|
try {
|
|
// AuthService 인스턴스 가져오기
|
|
final authService = AuthService();
|
|
|
|
// 로그아웃 처리
|
|
await authService.logout();
|
|
|
|
// 전역 네비게이터 키를 사용하여 로그인 화면으로 이동
|
|
if (navigatorKey.currentContext != null) {
|
|
Navigator.of(navigatorKey.currentContext!).pushAndRemoveUntil(
|
|
MaterialPageRoute(builder: (context) => const LoginScreen()),
|
|
(route) => false,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
print('로그아웃 처리 중 오류 발생: $e');
|
|
}
|
|
});
|
|
}
|
|
}
|