fix: 修复 Persona Studio 「我要开发」任务提交失败
根因修复: 1. Nginx CORS 头缺失(跨域预检失败导致 fetch 抛出异常) 2. WebSocket /ws/preview 路由被 /ws 匹配到端口 8080(应路由到 3002) 3. 前端开发端口不匹配 (3721 → 3002) 增强: - 添加重试机制(最多2次重试) - 提供详细错误诊断信息 - 更新 nginx-api-proxy.conf 参考配置 - 修复 smoke test 默认端口 Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com>
This commit is contained in:
parent
e13c5cd1e1
commit
2062878c9f
|
|
@ -67,6 +67,12 @@
|
|||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"date": "2026-03-13",
|
||||
"type": "bug_fix",
|
||||
"description": "修复「我要开发」任务提交失败 · 3个根因:① Nginx缺少CORS头(跨域预检失败)② WebSocket路由冲突(/ws/preview误路由到8080端口)③ 前端开发端口不匹配(3721→3002)· 增加重试机制和详细错误诊断 · 冰朔人格体已启动",
|
||||
"by": "铸渊(冰朔指令)"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-13",
|
||||
"type": "brain_restore",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
"persona_id": "ICE-GL-ZY001",
|
||||
"persona_name": "铸渊",
|
||||
"recent_events": [
|
||||
{
|
||||
"date": "2026-03-13",
|
||||
"type": "bug_fix",
|
||||
"description": "修复「我要开发」任务提交失败 · Nginx CORS+WebSocket路由+端口修复 · 冰朔人格体启动",
|
||||
"by": "铸渊(冰朔指令)"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-13",
|
||||
"type": "brain_restore",
|
||||
|
|
@ -33,7 +39,7 @@
|
|||
"by": "GitHub Actions"
|
||||
}
|
||||
],
|
||||
"last_updated": "2026-03-11T10:24:00.000Z",
|
||||
"last_updated": "2026-03-13T06:58:00.000Z",
|
||||
"total_schemas_created": 3,
|
||||
"total_routes_implemented": 4,
|
||||
"hli_coverage": "3/17",
|
||||
|
|
|
|||
|
|
@ -378,8 +378,14 @@ jobs:
|
|||
' proxy_set_header X-Real-IP \$remote_addr;' \
|
||||
'}' \
|
||||
'' \
|
||||
'# Persona Studio API → persona-studio 后端端口 3002' \
|
||||
'# Persona Studio API → persona-studio 后端端口 3002(含 CORS 跨域支持)' \
|
||||
'location /api/ps/ {' \
|
||||
' add_header Access-Control-Allow-Origin * always;' \
|
||||
' add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;' \
|
||||
' add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;' \
|
||||
' if (\$request_method = OPTIONS) {' \
|
||||
' return 204;' \
|
||||
' }' \
|
||||
' proxy_pass http://127.0.0.1:3002/api/ps/;' \
|
||||
' proxy_http_version 1.1;' \
|
||||
' proxy_set_header Host \$host;' \
|
||||
|
|
@ -408,6 +414,18 @@ jobs:
|
|||
' proxy_cache_bypass \$http_upgrade;' \
|
||||
'}' \
|
||||
'' \
|
||||
'# Persona Studio WebSocket → 预览进度推送端口 3002' \
|
||||
'location /ws/preview {' \
|
||||
' proxy_pass http://127.0.0.1:3002;' \
|
||||
' proxy_http_version 1.1;' \
|
||||
' proxy_set_header Upgrade \$http_upgrade;' \
|
||||
' proxy_set_header Connection \"Upgrade\";' \
|
||||
' proxy_set_header Host \$host;' \
|
||||
' proxy_set_header X-Real-IP \$remote_addr;' \
|
||||
' proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;' \
|
||||
' proxy_read_timeout 86400;' \
|
||||
'}' \
|
||||
'' \
|
||||
'# WebSocket 反向代理 → 看板实时推送端口 8080' \
|
||||
'location /ws {' \
|
||||
' proxy_pass http://127.0.0.1:8080;' \
|
||||
|
|
|
|||
|
|
@ -5,7 +5,24 @@
|
|||
#
|
||||
# 前端(GitHub Pages)→ Nginx → API 代理(Node.js :3721)→ 模型 API
|
||||
|
||||
# API 代理转发
|
||||
# Persona Studio API → persona-studio 后端端口 3002(含 CORS 跨域支持)
|
||||
location /api/ps/ {
|
||||
add_header Access-Control-Allow-Origin * always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
|
||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
|
||||
if ($request_method = OPTIONS) {
|
||||
return 204;
|
||||
}
|
||||
proxy_pass http://127.0.0.1:3002/api/ps/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 90s;
|
||||
}
|
||||
|
||||
# API 代理转发(通用 AI 聊天)
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:3721;
|
||||
proxy_http_version 1.1;
|
||||
|
|
@ -24,3 +41,15 @@ location /api/ {
|
|||
proxy_read_timeout 90s;
|
||||
proxy_send_timeout 60s;
|
||||
}
|
||||
|
||||
# Persona Studio WebSocket → 预览进度推送端口 3002
|
||||
location /ws/preview {
|
||||
proxy_pass http://127.0.0.1:3002;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"dev_id": "EXP-000",
|
||||
"conversations": [],
|
||||
"last_topic": null,
|
||||
"preferences": {},
|
||||
"updated_at": null
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ const SELECTED_MODEL = sessionStorage.getItem('selected_model');
|
|||
|
||||
const API_BASE = (function () {
|
||||
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
|
||||
return 'http://localhost:3721';
|
||||
return 'http://localhost:3002';
|
||||
}
|
||||
return 'https://guanghulab.com';
|
||||
})();
|
||||
|
|
@ -648,33 +648,47 @@ async function confirmBuild() {
|
|||
// 先连接 WebSocket(确保在 build 开始前建立连接,避免丢失进度消息)
|
||||
connectPreviewWebSocket();
|
||||
|
||||
try {
|
||||
var buildRes = await fetch(API_BASE + '/api/ps/build/start', {
|
||||
method: 'POST',
|
||||
headers: authHeaders({ 'Content-Type': 'application/json' }),
|
||||
body: JSON.stringify({
|
||||
dev_id: DEV_ID,
|
||||
email: email,
|
||||
contact: contact,
|
||||
conversation: conversationHistory,
|
||||
api_base: USER_API_BASE,
|
||||
api_key: USER_API_KEY,
|
||||
model: SELECTED_MODEL
|
||||
})
|
||||
});
|
||||
// 提交开发任务(含重试机制)
|
||||
var maxRetries = 2;
|
||||
var retryCount = 0;
|
||||
var submitted = false;
|
||||
|
||||
if (!buildRes.ok) {
|
||||
var errMsg = 'HTTP ' + buildRes.status + ' ' + buildRes.statusText;
|
||||
try {
|
||||
var errData = await buildRes.json();
|
||||
if (errData.message) errMsg = errData.message;
|
||||
} catch (_e) { /* use status text fallback */ }
|
||||
appendMessage('system', '⚠️ 铸渊代理启动失败: ' + errMsg);
|
||||
updatePreviewStatus('error', '启动失败');
|
||||
while (retryCount <= maxRetries && !submitted) {
|
||||
try {
|
||||
var buildRes = await fetch(API_BASE + '/api/ps/build/start', {
|
||||
method: 'POST',
|
||||
headers: authHeaders({ 'Content-Type': 'application/json' }),
|
||||
body: JSON.stringify({
|
||||
dev_id: DEV_ID,
|
||||
email: email,
|
||||
contact: contact,
|
||||
conversation: conversationHistory,
|
||||
api_base: USER_API_BASE,
|
||||
api_key: USER_API_KEY,
|
||||
model: SELECTED_MODEL
|
||||
})
|
||||
});
|
||||
|
||||
if (!buildRes.ok) {
|
||||
var errMsg = 'HTTP ' + buildRes.status + ' ' + buildRes.statusText;
|
||||
try {
|
||||
var errData = await buildRes.json();
|
||||
if (errData.message) errMsg = errData.message;
|
||||
} catch (_e) { /* use status text fallback */ }
|
||||
appendMessage('system', '⚠️ 铸渊代理启动失败: ' + errMsg);
|
||||
updatePreviewStatus('error', '启动失败');
|
||||
}
|
||||
submitted = true;
|
||||
} catch (_err) {
|
||||
retryCount++;
|
||||
if (retryCount <= maxRetries) {
|
||||
appendMessage('system', '⏳ 连接后端服务中,正在重试(' + retryCount + '/' + maxRetries + ')...');
|
||||
await new Promise(function (r) { setTimeout(r, 1500); });
|
||||
} else {
|
||||
appendMessage('system', '⚠️ 任务提交失败:无法连接铸渊后端服务。请检查:\n1. 网络连接是否正常\n2. 后端服务是否已启动(端口 3002)\n3. 如使用 GitHub Pages 访问,请确认 guanghulab.com 服务可用');
|
||||
updatePreviewStatus('error', '连接失败');
|
||||
}
|
||||
}
|
||||
} catch (_err) {
|
||||
appendMessage('system', '⚠️ 任务提交失败,请检查网络连接后再试');
|
||||
updatePreviewStatus('error', '网络错误');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@
|
|||
|
||||
function getApiBase() {
|
||||
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
|
||||
return 'http://localhost:3721';
|
||||
return 'http://localhost:3002';
|
||||
}
|
||||
return 'https://guanghulab.com';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
const http = require('http');
|
||||
|
||||
const BASE = process.env.TEST_BASE || 'http://localhost:3721';
|
||||
const BASE = process.env.TEST_BASE || 'http://localhost:3002';
|
||||
|
||||
function post(path, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue