feat: 초기 프로젝트 설정 및 LunchPick 앱 구현
LunchPick(오늘 뭐 먹Z?) Flutter 앱의 초기 구현입니다. 주요 기능: - 네이버 지도 연동 맛집 추가 - 랜덤 메뉴 추천 시스템 - 날씨 기반 거리 조정 - 방문 기록 관리 - Bluetooth 맛집 공유 - 다크모드 지원 기술 스택: - Flutter 3.8.1+ - Riverpod 상태 관리 - Hive 로컬 DB - Clean Architecture 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
101
lib/data/api/naver/naver_proxy_client.dart
Normal file
101
lib/data/api/naver/naver_proxy_client.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../../../core/network/network_client.dart';
|
||||
import '../../../core/network/network_config.dart';
|
||||
import '../../../core/errors/network_exceptions.dart';
|
||||
|
||||
/// 네이버 프록시 클라이언트
|
||||
///
|
||||
/// 웹 환경에서 CORS 문제를 해결하기 위한 프록시 클라이언트입니다.
|
||||
class NaverProxyClient {
|
||||
final NetworkClient _networkClient;
|
||||
|
||||
NaverProxyClient({NetworkClient? networkClient})
|
||||
: _networkClient = networkClient ?? NetworkClient();
|
||||
|
||||
/// 웹 환경에서 프록시를 통해 HTML 가져오기
|
||||
Future<String> fetchViaProxy(String url) async {
|
||||
if (!kIsWeb) {
|
||||
throw UnsupportedError('프록시는 웹 환경에서만 사용 가능합니다');
|
||||
}
|
||||
|
||||
try {
|
||||
final proxyUrl = NetworkConfig.getCorsProxyUrl(url);
|
||||
debugPrint('Using proxy URL: $proxyUrl');
|
||||
|
||||
final response = await _networkClient.get<String>(
|
||||
proxyUrl,
|
||||
options: Options(
|
||||
responseType: ResponseType.plain,
|
||||
headers: {
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
'Accept-Language': 'ko-KR,ko;q=0.9,en;q=0.8',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (response.data == null || response.data!.isEmpty) {
|
||||
throw ParseException(
|
||||
message: '프록시 응답이 비어있습니다',
|
||||
);
|
||||
}
|
||||
|
||||
return response.data!;
|
||||
} on DioException catch (e) {
|
||||
debugPrint('Proxy fetch error: ${e.message}');
|
||||
debugPrint('Status code: ${e.response?.statusCode}');
|
||||
debugPrint('Response: ${e.response?.data}');
|
||||
|
||||
if (e.response?.statusCode == 403) {
|
||||
throw ServerException(
|
||||
message: 'CORS 프록시 접근이 거부되었습니다. 잠시 후 다시 시도해주세요.',
|
||||
statusCode: 403,
|
||||
originalError: e,
|
||||
);
|
||||
}
|
||||
|
||||
throw ServerException(
|
||||
message: '프록시를 통한 페이지 로드에 실패했습니다',
|
||||
statusCode: e.response?.statusCode ?? 500,
|
||||
originalError: e,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 프록시 상태 확인
|
||||
Future<bool> checkProxyStatus() async {
|
||||
if (!kIsWeb) {
|
||||
return true; // 웹이 아니면 프록시 불필요
|
||||
}
|
||||
|
||||
try {
|
||||
final testUrl = 'https://map.naver.com';
|
||||
final proxyUrl = NetworkConfig.getCorsProxyUrl(testUrl);
|
||||
|
||||
final response = await _networkClient.head(
|
||||
proxyUrl,
|
||||
options: Options(
|
||||
validateStatus: (status) => status! < 500,
|
||||
),
|
||||
);
|
||||
|
||||
return response.statusCode == 200;
|
||||
} catch (e) {
|
||||
debugPrint('Proxy status check failed: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 프록시 URL 생성
|
||||
String getProxyUrl(String originalUrl) {
|
||||
if (!kIsWeb) {
|
||||
return originalUrl;
|
||||
}
|
||||
return NetworkConfig.getCorsProxyUrl(originalUrl);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
// 필요시 리소스 정리
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user