// api-config.js - nginx 프록시 대응 API 설정 function getApiBaseUrl() { const hostname = window.location.hostname; const protocol = window.location.protocol; const port = window.location.port; console.log('🌐 감지된 환경:', { hostname, protocol, port }); // 🔗 nginx 프록시를 통한 접근 (권장) // nginx가 /api/ 요청을 백엔드로 프록시하므로 포트 없이 접근 if (hostname.startsWith('192.168.') || hostname.startsWith('10.') || hostname.startsWith('172.') || hostname === 'localhost' || hostname === '127.0.0.1' || hostname.includes('.local') || hostname.includes('hyungi')) { // 현재 웹서버의 도메인/IP를 그대로 사용하되 API 포트(20005)로 직접 연결 const baseUrl = `${protocol}//${hostname}:20005/api`; console.log('✅ nginx 프록시 사용:', baseUrl); return baseUrl; } // 🚨 백업: 직접 접근 (nginx 프록시 실패시에만) console.warn('⚠️ 직접 API 접근 (백업 모드)'); return `${protocol}//${hostname}:20005/api`; } // API 설정 const API_URL = getApiBaseUrl(); export const API = API_URL; export const API_BASE_URL = API_URL; export function ensureAuthenticated() { const token = localStorage.getItem('token'); if (!token || token === 'undefined') { alert('로그인이 필요합니다'); localStorage.removeItem('token'); window.location.href = '/'; return null; } return token; } export function getAuthHeaders() { const token = localStorage.getItem('token'); return { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }; } // 🔧 개선된 API 호출 함수 (에러 처리 강화) export async function apiCall(url, options = {}) { const defaultOptions = { headers: getAuthHeaders() }; const finalOptions = { ...defaultOptions, ...options, headers: { ...defaultOptions.headers, ...options.headers } }; try { console.log(`📡 API 호출: ${url}`); const response = await fetch(url, finalOptions); // 인증 만료 처리 if (response.status === 401) { console.error('❌ 인증 만료'); localStorage.removeItem('token'); alert('인증이 만료되었습니다. 다시 로그인해주세요.'); window.location.href = '/'; return; } // 응답 실패 처리 if (!response.ok) { let errorMessage = `HTTP ${response.status}`; try { const errorData = await response.json(); errorMessage = errorData.error || errorData.message || errorMessage; } catch (e) { // JSON 파싱 실패시 기본 메시지 사용 } throw new Error(errorMessage); } const result = await response.json(); console.log(`✅ API 성공: ${url}`); return result; } catch (error) { console.error(`❌ API 오류 (${url}):`, error); // 네트워크 오류 vs 서버 오류 구분 if (error.name === 'TypeError' && error.message.includes('fetch')) { throw new Error('네트워크 연결 오류입니다. 인터넷 연결을 확인해주세요.'); } throw error; } } // 디버깅 정보 console.log('🔗 API Base URL:', API); console.log('🌐 Current Location:', { hostname: window.location.hostname, protocol: window.location.protocol, port: window.location.port, href: window.location.href }); // 🧪 API 연결 테스트 함수 (개발용) export async function testApiConnection() { try { console.log('🧪 API 연결 테스트 시작...'); const response = await fetch(`${API}/health`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); if (response.ok) { console.log('✅ API 연결 성공!'); return true; } else { console.log('❌ API 연결 실패:', response.status); return false; } } catch (error) { console.log('❌ API 연결 오류:', error.message); return false; } } // 개발 모드에서 자동 테스트 if (window.location.hostname === 'localhost' || window.location.hostname.startsWith('192.168.')) { setTimeout(() => { testApiConnection(); }, 1000); }