feat: 优化网络绑定配置支持外部访问

主要修改点:
1. 网络绑定调整
   - .env.example: WEB_HOST/VITE_WEB_HOST 从 127.0.0.1 改为 0.0.0.0
   - server/src/app/core/config.py: 默认 web_host 从 127.0.0.1 改为 0.0.0.0
   - web/package.json: Vite 脚本 host 从 127.0.0.1 改为 0.0.0.0
   - web/vite.config.js: normalizeState 中 WEB_HOST 默认值从 127.0.0.1 改为 0.0.0.0

2. CORS 配置扩展
   - .env.example: CORS_ORIGINS 添加 http://0.0.0.0:5173

3. Shell 脚本权限修复
   - server/start.sh, start.sh: 添加可执行权限 (644 -> 755)

4. Setup 表单与验证逻辑简化
   - web/src/composables/useSetupView.js:
     - 新增 readCurrentWebEndpoint() 从 window.location 自动检测当前 web host/port
     - 简化 runtimeInputsReady: 移除 web_host/web_port 必填验证,仅保留 server_host/server_port
     - 简化 buildRuntimeFingerprint(): 移除 web_host/web_port
     - buildPayload() 改用 readCurrentWebEndpoint() 解析 web 配置
   - web/vite.config.js:
     - 新增 resolveRuntimePayload(): 运行时解析 web_host/web_port
     - 移除 validateRuntimePayload() 中的 web_host/web_port 字段验证
     - 移除 testRuntimePorts() 中 web 端口冲突检测逻辑
     - 移除 canReuseCurrentWebPort() 函数

5. CSS 清理
   - web/src/assets/styles/views/setup-view.css: 移除未使用的 .setup-summary-grid 和 .setup-summary-item 样式
This commit is contained in:
2026-05-08 09:27:45 +08:00
parent adda87a01d
commit 828e8f5aaf
11 changed files with 61 additions and 132 deletions

View File

@@ -309,7 +309,7 @@ function normalizeState(env) {
configured: Boolean(readAdminSecret())
},
web: {
host: env.WEB_HOST || '127.0.0.1',
host: env.WEB_HOST || '0.0.0.0',
port: Number(env.WEB_PORT || 5173)
},
server: {
@@ -350,7 +350,6 @@ function sendJson(res, statusCode, payload) {
function validateRuntimePayload(payload) {
const fields = [
['web_host', 'Web Host'],
['server_host', 'Server Host']
]
@@ -361,7 +360,6 @@ function validateRuntimePayload(payload) {
}
const portFields = [
['web_port', 'Web Port'],
['server_port', 'Server Port']
]
@@ -376,6 +374,14 @@ function validateRuntimePayload(payload) {
return ''
}
function resolveRuntimePayload(payload, currentEnv) {
return {
...payload,
web_host: String(payload.web_host || currentEnv.WEB_HOST || '0.0.0.0').trim(),
web_port: Number(payload.web_port || currentEnv.WEB_PORT || 5173)
}
}
function validateDatabasePayload(payload) {
const fields = [
['postgres_host', 'PostgreSQL Host'],
@@ -444,13 +450,6 @@ function validateSetupPayload(payload) {
return validateIdentityPayload(payload) || validateRuntimePayload(payload) || validateDatabasePayload(payload)
}
function canReuseCurrentWebPort(payload, currentEnv) {
return (
Number(payload.web_port) === Number(currentEnv.WEB_PORT || 5173) &&
hostsConflict(String(payload.web_host || '').trim(), currentEnv.WEB_HOST || '127.0.0.1')
)
}
async function assertPortAvailable(host, port) {
await new Promise((resolve, reject) => {
const tester = net.createServer()
@@ -468,7 +467,7 @@ async function assertPortAvailable(host, port) {
})
}
async function testRuntimePorts(payload, currentEnv) {
async function testRuntimePorts(payload) {
const webPort = Number(payload.web_port)
const serverPort = Number(payload.server_port)
const webHost = String(payload.web_host || '').trim()
@@ -478,14 +477,6 @@ async function testRuntimePorts(payload, currentEnv) {
throw new Error('Web 与 Server 不能使用同一个主机与端口组合。')
}
if (!canReuseCurrentWebPort(payload, currentEnv)) {
try {
await assertPortAvailable(webHost, webPort)
} catch {
throw new Error(`Web 端口 ${webHost}:${webPort} 已被占用。`)
}
}
try {
await assertPortAvailable(serverHost, serverPort)
} catch {
@@ -569,7 +560,7 @@ function localSetupPlugin() {
return
}
const payload = await readJsonBody(req)
const payload = resolveRuntimePayload(await readJsonBody(req), readEnvState())
const validationError = validateRuntimePayload(payload)
if (validationError) {
@@ -578,8 +569,8 @@ function localSetupPlugin() {
}
try {
await testRuntimePorts(payload, readEnvState())
sendJson(res, 200, { ok: true, detail: '端口占用检测通过。' })
await testRuntimePorts(payload)
sendJson(res, 200, { ok: true, detail: 'Server 端口占用检测通过。' })
} catch (error) {
sendJson(res, 400, {
ok: false,
@@ -636,7 +627,8 @@ function localSetupPlugin() {
return
}
const payload = await readJsonBody(req)
const currentEnv = readEnvState()
const payload = resolveRuntimePayload(await readJsonBody(req), currentEnv)
const validationError = validateSetupPayload(payload)
if (validationError) {
@@ -645,7 +637,7 @@ function localSetupPlugin() {
}
try {
await testRuntimePorts(payload, readEnvState())
await testRuntimePorts(payload)
await testDatabaseConnection(payload)
} catch (error) {
sendJson(res, 400, {
@@ -656,7 +648,6 @@ function localSetupPlugin() {
persistAdminCredentials(payload)
const currentEnv = readEnvState()
const apiBaseUrl = buildApiBaseUrl(payload, currentEnv)
updateEnvFile({