Improve Supabase connection testing
Enhance the Supabase connection test to provide more detailed error information and handle potential CORS issues.
This commit is contained in:
@@ -1,15 +1,17 @@
|
|||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { RefreshCw, Info } from "lucide-react";
|
import { RefreshCw, Info, HelpCircle, AlertCircle } from "lucide-react";
|
||||||
import { toast } from "@/hooks/useToast.wrapper";
|
import { toast } from "@/hooks/useToast.wrapper";
|
||||||
import { testSupabaseConnection } from '@/lib/supabase';
|
import { testSupabaseConnection } from '@/lib/supabase';
|
||||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
||||||
|
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
|
||||||
|
|
||||||
interface TestResult {
|
interface TestResult {
|
||||||
url: string;
|
url: string;
|
||||||
proxyUrl: string;
|
proxyUrl: string;
|
||||||
usingProxy: boolean;
|
usingProxy: boolean;
|
||||||
|
proxyType?: string;
|
||||||
client: boolean;
|
client: boolean;
|
||||||
restApi: boolean;
|
restApi: boolean;
|
||||||
auth: boolean;
|
auth: boolean;
|
||||||
@@ -53,6 +55,13 @@ const SupabaseConnectionTest: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasProxyRecommendation = (errors: string[]) => {
|
||||||
|
return errors.some(err =>
|
||||||
|
err.includes('프록시 사용 시 정상 작동합니다') ||
|
||||||
|
err.includes('프록시를 선택해보세요')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold mb-4">연결 테스트</h2>
|
<h2 className="text-lg font-semibold mb-4">연결 테스트</h2>
|
||||||
@@ -99,18 +108,49 @@ const SupabaseConnectionTest: React.FC = () => {
|
|||||||
|
|
||||||
{testResults.usingProxy && (
|
{testResults.usingProxy && (
|
||||||
<div className="bg-blue-50 border border-blue-200 rounded p-2 mt-2">
|
<div className="bg-blue-50 border border-blue-200 rounded p-2 mt-2">
|
||||||
<p className="text-xs">CORS 프록시 사용 중: {testResults.proxyUrl}</p>
|
<p className="text-xs">CORS 프록시 사용 중: {testResults.proxyType || 'corsproxy.io'}</p>
|
||||||
|
<p className="text-xs break-all mt-1">{testResults.proxyUrl}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{testResults.errors.length > 0 && hasProxyRecommendation(testResults.errors) && (
|
||||||
|
<Alert className="bg-amber-50 border-amber-200 mt-3">
|
||||||
|
<AlertCircle className="h-4 w-4 text-amber-600" />
|
||||||
|
<AlertTitle className="text-amber-800 text-xs font-medium">프록시 변경 권장</AlertTitle>
|
||||||
|
<AlertDescription className="text-amber-700 text-xs">
|
||||||
|
{testResults.errors.find(err =>
|
||||||
|
err.includes('프록시 사용 시 정상 작동합니다') ||
|
||||||
|
err.includes('프록시를 선택해보세요')
|
||||||
|
)}
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
{testResults.errors.length > 0 && (
|
{testResults.errors.length > 0 && (
|
||||||
<div className="bg-red-50 border border-red-200 rounded p-2 mt-2">
|
<div className="bg-red-50 border border-red-200 rounded p-2 mt-2">
|
||||||
{testResults.errors.map((error: string, index: number) => (
|
{testResults.errors.map((error: string, index: number) => (
|
||||||
<p key={index} className="text-xs text-red-600">{error}</p>
|
<p key={index} className="text-xs text-red-600 mb-1">{error}</p>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 오류 해결 팁 */}
|
||||||
|
{!testResults.restApi && testResults.auth && (
|
||||||
|
<div className="bg-yellow-50 border border-yellow-200 rounded p-2 mt-2">
|
||||||
|
<div className="flex items-start gap-1">
|
||||||
|
<HelpCircle className="h-4 w-4 text-yellow-600 mt-0.5 flex-shrink-0" />
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-yellow-800 font-medium">인증은 성공했지만 API/DB 연결에 실패했습니다</p>
|
||||||
|
<ul className="list-disc text-xs text-yellow-700 pl-4 mt-1">
|
||||||
|
<li>다른 CORS 프록시 옵션을 시도해보세요</li>
|
||||||
|
<li>Supabase 서버의 CORS 설정을 확인하세요</li>
|
||||||
|
<li>브라우저 개발자 도구에서 네트워크 탭을 확인하세요</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 디버그 정보 섹션 추가 */}
|
{/* 디버그 정보 섹션 추가 */}
|
||||||
{testResults.debugInfo && (
|
{testResults.debugInfo && (
|
||||||
<Collapsible
|
<Collapsible
|
||||||
@@ -139,6 +179,18 @@ const SupabaseConnectionTest: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{testResults.usingProxy && (
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">프록시 URL:</span>
|
||||||
|
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
||||||
|
{testResults.proxyUrl}
|
||||||
|
</div>
|
||||||
|
<div className="mt-1">
|
||||||
|
프록시 유형: {testResults.proxyType || 'corsproxy.io'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium">클라이언트 초기화:</span>
|
<span className="font-medium">클라이언트 초기화:</span>
|
||||||
<div className="mt-1 text-green-600">
|
<div className="mt-1 text-green-600">
|
||||||
@@ -146,6 +198,15 @@ const SupabaseConnectionTest: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{testResults.debugInfo.lastErrorDetails && (
|
||||||
|
<div>
|
||||||
|
<span className="font-medium">마지막 오류 상세:</span>
|
||||||
|
<div className="mt-1 bg-red-50 p-1 rounded break-all text-red-600">
|
||||||
|
{testResults.debugInfo.lastErrorDetails}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium">브라우저 정보:</span>
|
<span className="font-medium">브라우저 정보:</span>
|
||||||
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
<div className="mt-1 bg-gray-100 p-1 rounded break-all">
|
||||||
|
|||||||
@@ -5,8 +5,13 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { DatabaseIcon, Save, RefreshCw, Shield, AlertTriangle, Check } from "lucide-react";
|
import { DatabaseIcon, Save, RefreshCw, Shield, AlertTriangle, Check } from "lucide-react";
|
||||||
import { toast } from "@/hooks/useToast.wrapper";
|
import { toast } from "@/hooks/useToast.wrapper";
|
||||||
import { configureSupabase, isCorsProxyEnabled } from "@/lib/supabase/config";
|
import {
|
||||||
|
configureSupabase,
|
||||||
|
isCorsProxyEnabled,
|
||||||
|
getProxyType
|
||||||
|
} from "@/lib/supabase/config";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||||
|
|
||||||
interface SupabaseSettingsFormProps {
|
interface SupabaseSettingsFormProps {
|
||||||
onSaved: () => void;
|
onSaved: () => void;
|
||||||
@@ -16,6 +21,7 @@ const SupabaseSettingsForm: React.FC<SupabaseSettingsFormProps> = ({ onSaved })
|
|||||||
const [supabaseUrl, setSupabaseUrl] = useState('');
|
const [supabaseUrl, setSupabaseUrl] = useState('');
|
||||||
const [supabaseKey, setSupabaseKey] = useState('');
|
const [supabaseKey, setSupabaseKey] = useState('');
|
||||||
const [useProxy, setUseProxy] = useState(false);
|
const [useProxy, setUseProxy] = useState(false);
|
||||||
|
const [proxyType, setProxyType] = useState('corsproxy.io');
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
|
|
||||||
// 저장된 설정 불러오기
|
// 저장된 설정 불러오기
|
||||||
@@ -23,10 +29,12 @@ const SupabaseSettingsForm: React.FC<SupabaseSettingsFormProps> = ({ onSaved })
|
|||||||
const savedUrl = localStorage.getItem('supabase_url');
|
const savedUrl = localStorage.getItem('supabase_url');
|
||||||
const savedKey = localStorage.getItem('supabase_key');
|
const savedKey = localStorage.getItem('supabase_key');
|
||||||
const proxyEnabled = isCorsProxyEnabled();
|
const proxyEnabled = isCorsProxyEnabled();
|
||||||
|
const savedProxyType = getProxyType();
|
||||||
|
|
||||||
if (savedUrl) setSupabaseUrl(savedUrl);
|
if (savedUrl) setSupabaseUrl(savedUrl);
|
||||||
if (savedKey) setSupabaseKey(savedKey);
|
if (savedKey) setSupabaseKey(savedKey);
|
||||||
setUseProxy(proxyEnabled);
|
setUseProxy(proxyEnabled);
|
||||||
|
setProxyType(savedProxyType);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const validateUrl = (url: string): boolean => {
|
const validateUrl = (url: string): boolean => {
|
||||||
@@ -57,7 +65,7 @@ const SupabaseSettingsForm: React.FC<SupabaseSettingsFormProps> = ({ onSaved })
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Supabase 설정 적용
|
// Supabase 설정 적용
|
||||||
configureSupabase(supabaseUrl, supabaseKey, useProxy);
|
configureSupabase(supabaseUrl, supabaseKey, useProxy, proxyType);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "설정 저장 완료",
|
title: "설정 저장 완료",
|
||||||
@@ -153,6 +161,27 @@ const SupabaseSettingsForm: React.FC<SupabaseSettingsFormProps> = ({ onSaved })
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 프록시 서비스 선택 옵션 추가 */}
|
||||||
|
{useProxy && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="proxy-type" className="text-base">프록시 서비스 선택</Label>
|
||||||
|
<Select value={proxyType} onValueChange={setProxyType}>
|
||||||
|
<SelectTrigger id="proxy-type" className="w-full">
|
||||||
|
<SelectValue placeholder="프록시 서비스 선택" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="corsproxy.io">corsproxy.io (기본)</SelectItem>
|
||||||
|
<SelectItem value="thingproxy">thingproxy.freeboard.io</SelectItem>
|
||||||
|
<SelectItem value="allorigins">allorigins.win</SelectItem>
|
||||||
|
<SelectItem value="cors-anywhere">cors-anywhere.herokuapp.com</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<p className="text-xs text-gray-500 mt-1">
|
||||||
|
특정 프록시 서비스가 작동하지 않으면 다른 서비스를 시도해보세요.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
|
|||||||
@@ -6,15 +6,36 @@ export const getSupabaseUrl = () => {
|
|||||||
if (storedUrl) {
|
if (storedUrl) {
|
||||||
// CORS 프록시 설정 확인
|
// CORS 프록시 설정 확인
|
||||||
const useProxy = localStorage.getItem('use_cors_proxy') === 'true';
|
const useProxy = localStorage.getItem('use_cors_proxy') === 'true';
|
||||||
|
const proxyType = localStorage.getItem('proxy_type') || 'corsproxy.io';
|
||||||
|
|
||||||
if (useProxy) {
|
if (useProxy) {
|
||||||
// CORS 프록시 URL로 변환 (URL 구조 개선)
|
|
||||||
const cleanUrl = storedUrl.trim();
|
|
||||||
// URL에 이미 프로토콜이 포함되어 있는지 확인
|
// URL에 이미 프로토콜이 포함되어 있는지 확인
|
||||||
|
const cleanUrl = storedUrl.trim();
|
||||||
const hasProtocol = cleanUrl.startsWith('http://') || cleanUrl.startsWith('https://');
|
const hasProtocol = cleanUrl.startsWith('http://') || cleanUrl.startsWith('https://');
|
||||||
const urlForProxy = hasProtocol ? cleanUrl : `http://${cleanUrl}`;
|
const urlForProxy = hasProtocol ? cleanUrl : `http://${cleanUrl}`;
|
||||||
|
|
||||||
// 프록시 URL 생성 시 더 정확한 인코딩
|
// 선택된 프록시 타입에 따라 URL 생성
|
||||||
const proxyUrl = `https://corsproxy.io/?${encodeURIComponent(urlForProxy)}`;
|
let proxyUrl = '';
|
||||||
|
|
||||||
|
switch (proxyType) {
|
||||||
|
case 'corsproxy.io':
|
||||||
|
// 주의: 쿼리 파라미터가 포함된 URL에서 발생하는 문제를 해결하기 위해
|
||||||
|
// 전체 URL을 인코딩하고 끝에 슬래시 추가
|
||||||
|
proxyUrl = `https://corsproxy.io/?${encodeURIComponent(urlForProxy)}`;
|
||||||
|
break;
|
||||||
|
case 'thingproxy':
|
||||||
|
proxyUrl = `https://thingproxy.freeboard.io/fetch/${urlForProxy}`;
|
||||||
|
break;
|
||||||
|
case 'allorigins':
|
||||||
|
proxyUrl = `https://api.allorigins.win/raw?url=${encodeURIComponent(urlForProxy)}`;
|
||||||
|
break;
|
||||||
|
case 'cors-anywhere':
|
||||||
|
proxyUrl = `https://cors-anywhere.herokuapp.com/${urlForProxy}`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
proxyUrl = `https://corsproxy.io/?${encodeURIComponent(urlForProxy)}`;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('CORS 프록시 URL 생성:', proxyUrl);
|
console.log('CORS 프록시 URL 생성:', proxyUrl);
|
||||||
return proxyUrl;
|
return proxyUrl;
|
||||||
}
|
}
|
||||||
@@ -40,13 +61,23 @@ export const useCorsProxy = (enabled: boolean) => {
|
|||||||
localStorage.setItem('use_cors_proxy', enabled.toString());
|
localStorage.setItem('use_cors_proxy', enabled.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// CORS 프록시 유형 설정
|
||||||
|
export const setProxyType = (proxyType: string) => {
|
||||||
|
localStorage.setItem('proxy_type', proxyType);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 현재 사용 중인 프록시 유형 가져오기
|
||||||
|
export const getProxyType = () => {
|
||||||
|
return localStorage.getItem('proxy_type') || 'corsproxy.io';
|
||||||
|
};
|
||||||
|
|
||||||
// CORS 프록시 사용 여부 확인
|
// CORS 프록시 사용 여부 확인
|
||||||
export const isCorsProxyEnabled = () => {
|
export const isCorsProxyEnabled = () => {
|
||||||
return localStorage.getItem('use_cors_proxy') === 'true';
|
return localStorage.getItem('use_cors_proxy') === 'true';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 온프레미스 연결을 위한 설정 도우미 함수
|
// 온프레미스 연결을 위한 설정 도우미 함수
|
||||||
export const configureSupabase = (url: string, key: string, useProxy: boolean = false) => {
|
export const configureSupabase = (url: string, key: string, useProxy: boolean = false, proxyType: string = 'corsproxy.io') => {
|
||||||
// URL 정리 (앞뒤 공백 제거)
|
// URL 정리 (앞뒤 공백 제거)
|
||||||
const cleanUrl = url.trim();
|
const cleanUrl = url.trim();
|
||||||
|
|
||||||
@@ -59,6 +90,7 @@ export const configureSupabase = (url: string, key: string, useProxy: boolean =
|
|||||||
localStorage.setItem('supabase_url', normalizedUrl);
|
localStorage.setItem('supabase_url', normalizedUrl);
|
||||||
localStorage.setItem('supabase_key', key);
|
localStorage.setItem('supabase_key', key);
|
||||||
localStorage.setItem('use_cors_proxy', useProxy.toString());
|
localStorage.setItem('use_cors_proxy', useProxy.toString());
|
||||||
|
localStorage.setItem('proxy_type', proxyType);
|
||||||
|
|
||||||
// 페이지 새로고침 - 새로운 설정으로 Supabase 클라이언트 초기화
|
// 페이지 새로고침 - 새로운 설정으로 Supabase 클라이언트 초기화
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import { supabase } from './client';
|
import { supabase } from './client';
|
||||||
import { getSupabaseUrl, getSupabaseKey, getOriginalSupabaseUrl, isCorsProxyEnabled } from './config';
|
import { getSupabaseUrl, getSupabaseKey, getOriginalSupabaseUrl, isCorsProxyEnabled, getProxyType } from './config';
|
||||||
|
|
||||||
// 테스트용 직접 로그인 함수 (디버깅 전용)
|
// 테스트용 직접 로그인 함수 (디버깅 전용)
|
||||||
export const testSupabaseLogin = async (email: string, password: string) => {
|
export const testSupabaseLogin = async (email: string, password: string) => {
|
||||||
@@ -30,12 +30,14 @@ export const testSupabaseConnection = async () => {
|
|||||||
const originalUrl = getOriginalSupabaseUrl();
|
const originalUrl = getOriginalSupabaseUrl();
|
||||||
const proxyUrl = getSupabaseUrl();
|
const proxyUrl = getSupabaseUrl();
|
||||||
const usingProxy = isCorsProxyEnabled();
|
const usingProxy = isCorsProxyEnabled();
|
||||||
|
const proxyType = getProxyType();
|
||||||
const supabaseKey = getSupabaseKey();
|
const supabaseKey = getSupabaseKey();
|
||||||
|
|
||||||
const results = {
|
const results = {
|
||||||
url: originalUrl, // 원본 URL
|
url: originalUrl, // 원본 URL
|
||||||
proxyUrl: proxyUrl, // 프록시 적용된 URL
|
proxyUrl: proxyUrl, // 프록시 적용된 URL
|
||||||
usingProxy: usingProxy, // 프록시 사용 여부
|
usingProxy: usingProxy, // 프록시 사용 여부
|
||||||
|
proxyType: proxyType, // 프록시 유형
|
||||||
client: !!supabase,
|
client: !!supabase,
|
||||||
restApi: false,
|
restApi: false,
|
||||||
auth: false,
|
auth: false,
|
||||||
@@ -45,17 +47,20 @@ export const testSupabaseConnection = async () => {
|
|||||||
originalUrl,
|
originalUrl,
|
||||||
proxyUrl,
|
proxyUrl,
|
||||||
usingProxy,
|
usingProxy,
|
||||||
|
proxyType,
|
||||||
keyLength: supabaseKey.length,
|
keyLength: supabaseKey.length,
|
||||||
browserInfo: navigator.userAgent,
|
browserInfo: navigator.userAgent,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
backupProxySuccess: false // 타입 오류 수정: backupProxySuccess 속성 추가
|
backupProxySuccess: false, // 백업 프록시 성공 여부
|
||||||
|
lastErrorDetails: '' // 마지막 오류 상세 정보
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('연결 테스트 시작 - 설정 정보:', {
|
console.log('연결 테스트 시작 - 설정 정보:', {
|
||||||
originalUrl,
|
originalUrl,
|
||||||
proxyUrl,
|
proxyUrl,
|
||||||
usingProxy
|
usingProxy,
|
||||||
|
proxyType
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -90,40 +95,58 @@ export const testSupabaseConnection = async () => {
|
|||||||
} else {
|
} else {
|
||||||
errorBody = await response.text();
|
errorBody = await response.text();
|
||||||
console.warn(`REST API 테스트 실패 (시도 1) - 상태: ${response.status}, 오류: ${errorBody}`);
|
console.warn(`REST API 테스트 실패 (시도 1) - 상태: ${response.status}, 오류: ${errorBody}`);
|
||||||
|
results.debugInfo.lastErrorDetails = `상태 코드: ${response.status}, 응답: ${errorBody}`;
|
||||||
|
|
||||||
// 2번째 시도: corsproxy.io URL 직접 구성
|
// 2번째 시도: 다른 프록시 서비스 URL 직접 구성
|
||||||
if (usingProxy) {
|
if (usingProxy) {
|
||||||
const directProxyUrl = `https://corsproxy.io/?${encodeURIComponent(`${originalUrl}/rest/v1/`)}`;
|
// 서로 다른 프록시 서비스 시도
|
||||||
console.log('REST API 테스트 URL (시도 2 - 직접 프록시):', directProxyUrl);
|
const proxyOptions = [
|
||||||
|
{ name: 'thingproxy', url: `https://thingproxy.freeboard.io/fetch/${originalUrl}/rest/v1/` },
|
||||||
|
{ name: 'allorigins', url: `https://api.allorigins.win/raw?url=${encodeURIComponent(`${originalUrl}/rest/v1/`)}` },
|
||||||
|
{ name: 'cors-anywhere', url: `https://cors-anywhere.herokuapp.com/${originalUrl}/rest/v1/` }
|
||||||
|
];
|
||||||
|
|
||||||
try {
|
// 현재 사용 중인 프록시와 다른 프록시만 시도
|
||||||
response = await fetch(directProxyUrl, {
|
const alternateProxies = proxyOptions.filter(p => p.name !== proxyType);
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
for (const proxy of alternateProxies) {
|
||||||
'Content-Type': 'application/json',
|
console.log(`REST API 테스트 URL (시도 2 - ${proxy.name}):`, proxy.url);
|
||||||
'apikey': supabaseKey,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
try {
|
||||||
results.restApi = true;
|
response = await fetch(proxy.url, {
|
||||||
console.log('REST API 테스트 성공 (시도 2)');
|
method: 'GET',
|
||||||
} else {
|
headers: {
|
||||||
const error2 = await response.text();
|
'Content-Type': 'application/json',
|
||||||
console.warn(`REST API 테스트 실패 (시도 2) - 상태: ${response.status}, 오류: ${error2}`);
|
'apikey': supabaseKey,
|
||||||
results.errors.push(`REST API 오류(${response.status}): ${error2 || errorBody || '응답 없음'}`);
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
results.restApi = true;
|
||||||
|
results.debugInfo.backupProxySuccess = true;
|
||||||
|
console.log(`REST API 테스트 성공 (시도 2 - ${proxy.name})`);
|
||||||
|
results.errors.push(`REST API 성공: ${proxy.name} 프록시 사용 시 정상 작동합니다. 설정에서 이 프록시를 선택해보세요.`);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
const error2 = await response.text();
|
||||||
|
console.warn(`REST API 테스트 실패 (시도 2 - ${proxy.name}) - 상태: ${response.status}, 오류: ${error2}`);
|
||||||
|
}
|
||||||
|
} catch (innerErr: any) {
|
||||||
|
console.error(`REST API 테스트 시도 2 (${proxy.name}) 예외:`, innerErr);
|
||||||
}
|
}
|
||||||
} catch (innerErr: any) {
|
}
|
||||||
console.error('REST API 테스트 시도 2 예외:', innerErr);
|
|
||||||
results.errors.push(`REST API 예외 (시도 2): ${innerErr.message || '알 수 없는 오류'}`);
|
if (!results.restApi) {
|
||||||
|
results.errors.push(`REST API 오류(${response.status}): ${errorBody || '응답 없음'} - 다른 프록시 옵션도 모두 실패했습니다.`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
results.errors.push(`REST API 오류(${response.status}): ${errorBody || '응답 없음'}`);
|
results.errors.push(`REST API 오류(${response.status}): ${errorBody || '응답 없음'} - CORS 프록시 활성화를 시도해보세요.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (outerErr: any) {
|
} catch (outerErr: any) {
|
||||||
console.error('REST API 테스트 시도 1 예외:', outerErr);
|
console.error('REST API 테스트 시도 1 예외:', outerErr);
|
||||||
results.errors.push(`REST API 예외 (시도 1): ${outerErr.message || '알 수 없는 오류'}`);
|
results.errors.push(`REST API 예외 (시도 1): ${outerErr.message || '알 수 없는 오류'}`);
|
||||||
|
results.debugInfo.lastErrorDetails = outerErr.message || '알 수 없는 오류';
|
||||||
|
|
||||||
// 백업 시도
|
// 백업 시도
|
||||||
if (usingProxy) {
|
if (usingProxy) {
|
||||||
@@ -144,6 +167,7 @@ export const testSupabaseConnection = async () => {
|
|||||||
results.restApi = true;
|
results.restApi = true;
|
||||||
console.log('REST API 테스트 성공 (백업 프록시)');
|
console.log('REST API 테스트 성공 (백업 프록시)');
|
||||||
results.debugInfo.backupProxySuccess = true;
|
results.debugInfo.backupProxySuccess = true;
|
||||||
|
results.errors.push('REST API 성공: allorigins 프록시 사용 시 정상 작동합니다. 설정에서 이 프록시를 선택해보세요.');
|
||||||
} else {
|
} else {
|
||||||
const backupError = await response.text();
|
const backupError = await response.text();
|
||||||
console.warn(`REST API 테스트 실패 (백업 프록시) - 상태: ${response.status}, 오류: ${backupError}`);
|
console.warn(`REST API 테스트 실패 (백업 프록시) - 상태: ${response.status}, 오류: ${backupError}`);
|
||||||
@@ -184,7 +208,14 @@ export const testSupabaseConnection = async () => {
|
|||||||
|
|
||||||
results.database = !error;
|
results.database = !error;
|
||||||
if (error) {
|
if (error) {
|
||||||
results.errors.push(`데이터베이스 오류: ${error.message}`);
|
let errorMsg = error.message;
|
||||||
|
|
||||||
|
// 익명 인증 오류 처리
|
||||||
|
if (errorMsg.includes('Auth session missing') || errorMsg.includes('JWT')) {
|
||||||
|
errorMsg += ' - 로그인이 필요하거나 권한 설정을 확인해주세요.';
|
||||||
|
}
|
||||||
|
|
||||||
|
results.errors.push(`데이터베이스 오류: ${errorMsg}`);
|
||||||
console.error('데이터베이스 테스트 실패:', error);
|
console.error('데이터베이스 테스트 실패:', error);
|
||||||
} else {
|
} else {
|
||||||
console.log('데이터베이스 테스트 성공', data);
|
console.log('데이터베이스 테스트 성공', data);
|
||||||
|
|||||||
Reference in New Issue
Block a user