Update Supabase connection tests
Improve error handling for REST API and database connection tests.
This commit is contained in:
@@ -8,24 +8,25 @@ interface ProxyRecommendationAlertProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ProxyRecommendationAlert: React.FC<ProxyRecommendationAlertProps> = ({ errors }) => {
|
const ProxyRecommendationAlert: React.FC<ProxyRecommendationAlertProps> = ({ errors }) => {
|
||||||
const hasProxyRecommendation = errors.some(err =>
|
const hasCorsError = errors.some(err =>
|
||||||
err.includes('프록시 사용 시 정상 작동합니다') ||
|
err.includes('CORS') ||
|
||||||
err.includes('프록시를 선택해보세요')
|
err.includes('Failed to fetch') ||
|
||||||
|
err.includes('프록시 사용시 정상 작동') ||
|
||||||
|
err.includes('프록시를 활성화')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!hasProxyRecommendation || errors.length === 0) return null;
|
if (!hasCorsError || errors.length === 0) return null;
|
||||||
|
|
||||||
const recommendationMessage = errors.find(err =>
|
|
||||||
err.includes('프록시 사용 시 정상 작동합니다') ||
|
|
||||||
err.includes('프록시를 선택해보세요')
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Alert className="bg-amber-50 border-amber-200 mt-3">
|
<Alert className="bg-amber-50 border-amber-200 mt-3">
|
||||||
<AlertCircle className="h-4 w-4 text-amber-600" />
|
<AlertCircle className="h-4 w-4 text-amber-600" />
|
||||||
<AlertTitle className="text-amber-800 text-xs font-medium">프록시 변경 권장</AlertTitle>
|
<AlertTitle className="text-amber-800 text-xs font-medium">CORS 오류 감지됨</AlertTitle>
|
||||||
<AlertDescription className="text-amber-700 text-xs">
|
<AlertDescription className="text-amber-700 text-xs">
|
||||||
{recommendationMessage}
|
<p>HTTP URL에 대한 브라우저 보안 제한으로 인해 연결에 실패했습니다.</p>
|
||||||
|
<ul className="list-disc pl-4 mt-1">
|
||||||
|
<li className="mt-1">CORS 프록시를 활성화하고 프록시 유형을 변경해보세요.</li>
|
||||||
|
<li className="mt-1">또는 HTTPS URL로 변경하는 것을 고려하세요.</li>
|
||||||
|
</ul>
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const ProxyTypeSelector: React.FC<ProxyTypeSelectorProps> = ({
|
|||||||
<SelectItem value="thingproxy">thingproxy.freeboard.io</SelectItem>
|
<SelectItem value="thingproxy">thingproxy.freeboard.io</SelectItem>
|
||||||
<SelectItem value="allorigins">allorigins.win</SelectItem>
|
<SelectItem value="allorigins">allorigins.win</SelectItem>
|
||||||
<SelectItem value="cors-anywhere">cors-anywhere.herokuapp.com</SelectItem>
|
<SelectItem value="cors-anywhere">cors-anywhere.herokuapp.com</SelectItem>
|
||||||
|
<SelectItem value="cloudflare">Cloudflare Workers 프록시</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<p className="text-xs text-gray-500 mt-1">
|
<p className="text-xs text-gray-500 mt-1">
|
||||||
|
|||||||
@@ -31,6 +31,14 @@ export const getSupabaseUrl = () => {
|
|||||||
case 'cors-anywhere':
|
case 'cors-anywhere':
|
||||||
proxyUrl = `https://cors-anywhere.herokuapp.com/${urlForProxy}`;
|
proxyUrl = `https://cors-anywhere.herokuapp.com/${urlForProxy}`;
|
||||||
break;
|
break;
|
||||||
|
case 'cloudflare':
|
||||||
|
// Cloudflare Workers CORS 프록시
|
||||||
|
proxyUrl = `https://cors-proxy.azurewebsites.net/api/cors-proxy?url=${encodeURIComponent(urlForProxy)}`;
|
||||||
|
break;
|
||||||
|
case 'local-proxy':
|
||||||
|
// 사용자 지정 로컬 프록시 (개발 환경용)
|
||||||
|
proxyUrl = `http://localhost:8080/proxy?url=${encodeURIComponent(urlForProxy)}`;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
proxyUrl = `https://corsproxy.io/?${encodeURIComponent(urlForProxy)}`;
|
proxyUrl = `https://corsproxy.io/?${encodeURIComponent(urlForProxy)}`;
|
||||||
}
|
}
|
||||||
@@ -42,8 +50,7 @@ export const getSupabaseUrl = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 기본값 사용 (환경 변수 대신)
|
// 기본값 사용 (환경 변수 대신)
|
||||||
const defaultUrl = 'http://a11.ism.kr:8000';
|
return 'http://a11.ism.kr:8000';
|
||||||
return defaultUrl;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSupabaseKey = () => {
|
export const getSupabaseKey = () => {
|
||||||
@@ -85,6 +92,12 @@ export const configureSupabase = (url: string, key: string, useProxy: boolean =
|
|||||||
? cleanUrl
|
? cleanUrl
|
||||||
: `http://${cleanUrl}`;
|
: `http://${cleanUrl}`;
|
||||||
|
|
||||||
|
// HTTP URL을 사용하고 프록시가 활성화되지 않은 경우 경고
|
||||||
|
const isHttpUrl = normalizedUrl.startsWith('http:') && !normalizedUrl.startsWith('http://localhost');
|
||||||
|
if (isHttpUrl && !useProxy) {
|
||||||
|
console.warn('경고: HTTP URL을 사용하면서 CORS 프록시가 비활성화되어 있습니다. 브라우저에서 접근 문제가 발생할 수 있습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
// 로컬 스토리지에 설정 저장
|
// 로컬 스토리지에 설정 저장
|
||||||
localStorage.setItem('supabase_url', normalizedUrl);
|
localStorage.setItem('supabase_url', normalizedUrl);
|
||||||
localStorage.setItem('supabase_key', key);
|
localStorage.setItem('supabase_key', key);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export const testRestApi = async (
|
|||||||
try {
|
try {
|
||||||
const originalUrl = getSupabaseUrl();
|
const originalUrl = getSupabaseUrl();
|
||||||
const supabaseKey = getSupabaseKey();
|
const supabaseKey = getSupabaseKey();
|
||||||
const proxyType = 'corsproxy.io'; // 기본값
|
|
||||||
|
|
||||||
if (!originalUrl || !supabaseKey) {
|
if (!originalUrl || !supabaseKey) {
|
||||||
return {
|
return {
|
||||||
@@ -21,13 +20,32 @@ export const testRestApi = async (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTP URL 감지
|
||||||
|
const isHttpUrl = originalUrl.startsWith('http:') && !originalUrl.startsWith('http://localhost');
|
||||||
|
|
||||||
// 클라이언트 인스턴스로 간단한 API 호출 수행
|
// 클라이언트 인스턴스로 간단한 API 호출 수행
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('_tests')
|
.from('_tests')
|
||||||
.select('*')
|
.select('*')
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (error && error.code !== '42P01' && error.code !== 'PGRST116') {
|
if (error) {
|
||||||
|
// CORS 관련 오류인지 확인
|
||||||
|
if (error.message && error.message.includes('fetch failed') && isHttpUrl) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `REST API 요청 실패: ${error.message} (CORS 오류 가능성 높음. CORS 프록시 사용을 권장합니다)`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 테이블이 없는 경우 정상 (테스트 테이블이 없을 수 있음)
|
||||||
|
if (error.code === '42P01' || error.code === 'PGRST116') {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
error: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `REST API 요청 실패: ${error.message}`
|
error: `REST API 요청 실패: ${error.message}`
|
||||||
@@ -39,6 +57,17 @@ export const testRestApi = async (
|
|||||||
error: null
|
error: null
|
||||||
};
|
};
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
// HTTP URL을 사용하고 있는지 확인
|
||||||
|
const url = getSupabaseUrl();
|
||||||
|
const isHttpUrl = url.startsWith('http:') && !url.startsWith('http://localhost');
|
||||||
|
|
||||||
|
if (err.message && err.message.includes('Failed to fetch') && isHttpUrl) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `REST API 테스트 실패: ${err.message} (CORS 프록시 사용시 정상 작동합니다. 설정에서 프록시를 활성화해보세요)`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `REST API 테스트 예외: ${err.message || '알 수 없는 오류'}`
|
error: `REST API 테스트 예외: ${err.message || '알 수 없는 오류'}`
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
import { SupabaseClient } from '@supabase/supabase-js';
|
import { SupabaseClient } from '@supabase/supabase-js';
|
||||||
import { TestResult } from './types';
|
import { TestResult } from './types';
|
||||||
|
import { getSupabaseUrl } from '../config';
|
||||||
|
|
||||||
export const testDatabaseConnection = async (
|
export const testDatabaseConnection = async (
|
||||||
supabase: SupabaseClient
|
supabase: SupabaseClient
|
||||||
@@ -13,8 +14,16 @@ export const testDatabaseConnection = async (
|
|||||||
.limit(1)
|
.limit(1)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
// 오류가 있으면 실패로 처리 (404 제외 - 테이블이 없는 것은 정상)
|
// 테이블이 없는 경우 정상 (테스트 테이블이 없을 수 있음)
|
||||||
if (error && error.code !== '42P01' && error.code !== 'PGRST116') {
|
if (error && (error.code === '42P01' || error.code === 'PGRST116')) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
error: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 다른 오류가 있으면 실패로 처리
|
||||||
|
if (error) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `데이터베이스 연결 오류: ${error.message}`
|
error: `데이터베이스 연결 오류: ${error.message}`
|
||||||
@@ -27,6 +36,17 @@ export const testDatabaseConnection = async (
|
|||||||
error: null
|
error: null
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
// HTTP URL 관련 CORS 오류 확인
|
||||||
|
const url = getSupabaseUrl();
|
||||||
|
const isHttpUrl = url.startsWith('http:') && !url.startsWith('http://localhost');
|
||||||
|
|
||||||
|
if (error.message && error.message.includes('Failed to fetch') && isHttpUrl) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `데이터베이스 테스트 실패: ${error.message} (CORS 프록시 사용시 정상 작동합니다. 설정에서 프록시를 활성화해보세요)`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `데이터베이스 테스트 중 예외 발생: ${error.message || '알 수 없는 오류'}`
|
error: `데이터베이스 테스트 중 예외 발생: ${error.message || '알 수 없는 오류'}`
|
||||||
|
|||||||
Reference in New Issue
Block a user