284 lines
11 KiB
HTML
284 lines
11 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>CORS跨域测试页面</title>
|
||
<style>
|
||
body {
|
||
font-family: 'Microsoft YaHei', sans-serif;
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 20px;
|
||
background-color: #f5f5f5;
|
||
}
|
||
.container {
|
||
background: white;
|
||
padding: 30px;
|
||
border-radius: 10px;
|
||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||
}
|
||
.test-section {
|
||
margin: 20px 0;
|
||
padding: 20px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 5px;
|
||
background: #fafafa;
|
||
}
|
||
.btn {
|
||
background: #007bff;
|
||
color: white;
|
||
padding: 10px 20px;
|
||
border: none;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
margin: 5px;
|
||
}
|
||
.btn:hover {
|
||
background: #0056b3;
|
||
}
|
||
.btn.success {
|
||
background: #28a745;
|
||
}
|
||
.btn.error {
|
||
background: #dc3545;
|
||
}
|
||
.log {
|
||
background: #000;
|
||
color: #0f0;
|
||
padding: 15px;
|
||
border-radius: 5px;
|
||
font-family: 'Consolas', monospace;
|
||
height: 300px;
|
||
overflow-y: auto;
|
||
margin: 10px 0;
|
||
}
|
||
.status {
|
||
display: inline-block;
|
||
padding: 5px 10px;
|
||
border-radius: 3px;
|
||
margin: 5px;
|
||
font-weight: bold;
|
||
}
|
||
.status.success { background: #d4edda; color: #155724; }
|
||
.status.error { background: #f8d7da; color: #721c24; }
|
||
.status.warning { background: #fff3cd; color: #856404; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>🧪 CORS跨域请求测试</h1>
|
||
<p>测试药店销售预测系统API的跨域访问功能</p>
|
||
|
||
<div class="test-section">
|
||
<h3>📡 基础连接测试</h3>
|
||
<button class="btn" onclick="testBasicConnection()">测试基础连接</button>
|
||
<button class="btn" onclick="testCORSHeaders()">测试CORS头</button>
|
||
<button class="btn" onclick="testPreflightRequest()">测试预检请求</button>
|
||
<div id="connectionStatus"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h3>🔗 API端点测试</h3>
|
||
<button class="btn" onclick="testAPIEndpoints()">测试所有端点</button>
|
||
<button class="btn" onclick="testTrainingAPI()">测试训练API</button>
|
||
<button class="btn" onclick="testWebSocket()">测试WebSocket</button>
|
||
<div id="apiStatus"></div>
|
||
</div>
|
||
|
||
<div class="test-section">
|
||
<h3>📝 实时日志</h3>
|
||
<button class="btn" onclick="clearLog()">清空日志</button>
|
||
<div class="log" id="logOutput"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const API_BASE = 'http://127.0.0.1:5000';
|
||
const logOutput = document.getElementById('logOutput');
|
||
|
||
function log(message, type = 'info') {
|
||
const timestamp = new Date().toLocaleTimeString();
|
||
const color = type === 'error' ? '#ff6b6b' : type === 'success' ? '#51cf66' : '#74c0fc';
|
||
logOutput.innerHTML += `<div style="color: ${color};">[${timestamp}] ${message}</div>`;
|
||
logOutput.scrollTop = logOutput.scrollHeight;
|
||
}
|
||
|
||
function clearLog() {
|
||
logOutput.innerHTML = '';
|
||
}
|
||
|
||
function updateStatus(elementId, message, type) {
|
||
const element = document.getElementById(elementId);
|
||
element.innerHTML = `<span class="status ${type}">${message}</span>`;
|
||
}
|
||
|
||
async function testBasicConnection() {
|
||
log('🔍 开始基础连接测试...');
|
||
try {
|
||
const response = await fetch(`${API_BASE}/api/health`, {
|
||
method: 'GET',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
log('✅ 基础连接成功', 'success');
|
||
log(`📊 响应数据: ${JSON.stringify(data)}`);
|
||
updateStatus('connectionStatus', '连接正常', 'success');
|
||
} else {
|
||
log(`❌ 连接失败: HTTP ${response.status}`, 'error');
|
||
updateStatus('connectionStatus', `连接失败 (${response.status})`, 'error');
|
||
}
|
||
} catch (error) {
|
||
log(`❌ 连接错误: ${error.message}`, 'error');
|
||
updateStatus('connectionStatus', '连接失败', 'error');
|
||
}
|
||
}
|
||
|
||
async function testCORSHeaders() {
|
||
log('🌐 开始CORS头测试...');
|
||
try {
|
||
const response = await fetch(`${API_BASE}/api/health`, {
|
||
method: 'GET',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Origin': window.location.origin
|
||
}
|
||
});
|
||
|
||
const corsHeaders = {
|
||
'Access-Control-Allow-Origin': response.headers.get('Access-Control-Allow-Origin'),
|
||
'Access-Control-Allow-Methods': response.headers.get('Access-Control-Allow-Methods'),
|
||
'Access-Control-Allow-Headers': response.headers.get('Access-Control-Allow-Headers')
|
||
};
|
||
|
||
log('📋 CORS响应头:');
|
||
Object.entries(corsHeaders).forEach(([key, value]) => {
|
||
log(` ${key}: ${value || '未设置'}`);
|
||
});
|
||
|
||
if (corsHeaders['Access-Control-Allow-Origin']) {
|
||
log('✅ CORS头配置正常', 'success');
|
||
} else {
|
||
log('⚠️ CORS头可能缺失', 'error');
|
||
}
|
||
|
||
} catch (error) {
|
||
log(`❌ CORS测试失败: ${error.message}`, 'error');
|
||
}
|
||
}
|
||
|
||
async function testPreflightRequest() {
|
||
log('🚁 开始预检请求测试...');
|
||
try {
|
||
const response = await fetch(`${API_BASE}/api/training`, {
|
||
method: 'OPTIONS',
|
||
headers: {
|
||
'Origin': window.location.origin,
|
||
'Access-Control-Request-Method': 'POST',
|
||
'Access-Control-Request-Headers': 'Content-Type'
|
||
}
|
||
});
|
||
|
||
if (response.ok) {
|
||
log('✅ OPTIONS预检请求成功', 'success');
|
||
log(`📊 状态码: ${response.status}`);
|
||
} else {
|
||
log(`❌ OPTIONS预检失败: ${response.status}`, 'error');
|
||
}
|
||
} catch (error) {
|
||
log(`❌ 预检请求错误: ${error.message}`, 'error');
|
||
}
|
||
}
|
||
|
||
async function testAPIEndpoints() {
|
||
log('🔗 开始API端点测试...');
|
||
const endpoints = [
|
||
{ path: '/api/health', method: 'GET' },
|
||
{ path: '/api/training', method: 'GET' },
|
||
{ path: '/api/stores', method: 'GET' },
|
||
{ path: '/api/products', method: 'GET' }
|
||
];
|
||
|
||
let successCount = 0;
|
||
|
||
for (const endpoint of endpoints) {
|
||
try {
|
||
const response = await fetch(`${API_BASE}${endpoint.path}`, {
|
||
method: endpoint.method,
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
if (response.ok) {
|
||
log(`✅ ${endpoint.method} ${endpoint.path}: 成功`, 'success');
|
||
successCount++;
|
||
} else {
|
||
log(`❌ ${endpoint.method} ${endpoint.path}: HTTP ${response.status}`, 'error');
|
||
}
|
||
} catch (error) {
|
||
log(`❌ ${endpoint.method} ${endpoint.path}: ${error.message}`, 'error');
|
||
}
|
||
}
|
||
|
||
updateStatus('apiStatus', `${successCount}/${endpoints.length} 端点正常`,
|
||
successCount === endpoints.length ? 'success' : 'warning');
|
||
}
|
||
|
||
async function testTrainingAPI() {
|
||
log('🚀 开始训练API测试...');
|
||
const trainingData = {
|
||
product_id: 'P001',
|
||
model_type: 'transformer',
|
||
epochs: 1,
|
||
training_mode: 'product'
|
||
};
|
||
|
||
try {
|
||
const response = await fetch(`${API_BASE}/api/start_training`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(trainingData)
|
||
});
|
||
|
||
if (response.ok) {
|
||
const result = await response.json();
|
||
log('✅ 训练API调用成功', 'success');
|
||
log(`📋 任务ID: ${result.task_id || 'N/A'}`);
|
||
} else {
|
||
const errorText = await response.text();
|
||
log(`❌ 训练API失败: HTTP ${response.status}`, 'error');
|
||
log(`📄 错误详情: ${errorText}`);
|
||
}
|
||
} catch (error) {
|
||
log(`❌ 训练API错误: ${error.message}`, 'error');
|
||
}
|
||
}
|
||
|
||
function testWebSocket() {
|
||
log('🔌 开始WebSocket测试...');
|
||
try {
|
||
// 注意:浏览器环境中需要socket.io客户端库
|
||
log('⚠️ WebSocket测试需要socket.io客户端库', 'error');
|
||
log('💡 请在浏览器控制台中手动测试WebSocket连接');
|
||
log(`🔗 WebSocket地址: ws://127.0.0.1:5000/socket.io`);
|
||
} catch (error) {
|
||
log(`❌ WebSocket测试失败: ${error.message}`, 'error');
|
||
}
|
||
}
|
||
|
||
// 页面加载时自动运行基础测试
|
||
window.onload = function() {
|
||
log('🎉 CORS测试页面已加载');
|
||
log(`🎯 测试目标: ${API_BASE}`);
|
||
log('💡 点击按钮开始测试各项功能');
|
||
};
|
||
</script>
|
||
</body>
|
||
</html> |