From a6d9b6c418eb6499a67bdb2eb524d9a1395eebac Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Mon, 17 Aug 2026 15:44:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(server):=20=E4=BF=AE=E5=A4=8D=20serve-stati?= =?UTF-8?q?c=20=E4=B8=8D=E6=8E=A5=E5=8F=97=E6=95=B0=E7=BB=84=20root?= =?UTF-8?q?=E3=80=81=E6=94=B9=E4=B8=BA=E6=8C=89=E8=AF=B7=E6=B1=82=E9=80=90?= =?UTF-8?q?=E4=B8=AA=E6=8C=82=E8=BD=BD=EF=BC=8C=E9=81=BF=E5=85=8D=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E6=97=B6=20TypeError:=20root=20path=20must=20be=20a?= =?UTF-8?q?=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上一轮把 getBeepAudioDirs() 这个数组直接塞进 express.static(), 但 serve-static 签名要求 root 必须是字符串,会在 app 启动注册 中间件时直接抛错(甚至在接收请求前)。 修复方式: - /media/audio/general 和 /media/audio/beep 改为动态中间件: 请求进来时再依次对每个目录调用一次 express.static(root, {fallthrough}) - 单目录的 music/voice/line/station/temp 保留 express.static 但统一包一层 String(xxx || '') 保证就算路径解析异常也是空 字符串而不是 undefined - 后备的 7 条 app.get(':path(*)') 路由不变,仍然负责 sendBinaryFile / sendBinaryFileFromCandidates 兜底(含 range、Content-Length 等头) 客户端 bump v1.0.102 -> v1.0.103 --- CloudServer/server.js | 36 +++++++++++++++++++++++++++++------- station_broadcast.lua | 2 +- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/CloudServer/server.js b/CloudServer/server.js index 7c67dd1..6184dc4 100644 --- a/CloudServer/server.js +++ b/CloudServer/server.js @@ -148,13 +148,35 @@ function safeRelativeToBase(baseDir, relativePath) { return full; } -app.use('/media/audio/general', express.static(getBeepAudioDirs(), { fallthrough: true })); -app.use('/media/audio/beep', express.static(getBeepAudioDirs(), { fallthrough: true })); -app.use('/media/audio/music', express.static(audioMusicDir, { fallthrough: true })); -app.use('/media/audio/voice', express.static(audioVoiceDir, { fallthrough: true })); -app.use('/media/audio/line', express.static(audioLineDir, { fallthrough: true })); -app.use('/media/audio/station', express.static(audioStationDir, { fallthrough: true })); -app.use('/media/temp', express.static(tempBroadcastDir, { fallthrough: true })); +app.use('/media/audio/general', (req, res, next) => { + const dirs = getBeepAudioDirs(); + if (!dirs || dirs.length === 0) return next(); + let i = 0; + const tryNext = () => { + if (i >= dirs.length) return next(); + const dir = String(dirs[i++] || ''); + if (!dir) return tryNext(); + express.static(dir, { fallthrough: true })(req, res, tryNext); + }; + tryNext(); +}); +app.use('/media/audio/beep', (req, res, next) => { + const dirs = getBeepAudioDirs(); + if (!dirs || dirs.length === 0) return next(); + let i = 0; + const tryNext = () => { + if (i >= dirs.length) return next(); + const dir = String(dirs[i++] || ''); + if (!dir) return tryNext(); + express.static(dir, { fallthrough: true })(req, res, tryNext); + }; + tryNext(); +}); +app.use('/media/audio/music', express.static(String(audioMusicDir || ''), { fallthrough: true })); +app.use('/media/audio/voice', express.static(String(audioVoiceDir || ''), { fallthrough: true })); +app.use('/media/audio/line', express.static(String(audioLineDir || ''), { fallthrough: true })); +app.use('/media/audio/station', express.static(String(audioStationDir || ''), { fallthrough: true })); +app.use('/media/temp', express.static(String(tempBroadcastDir || ''), { fallthrough: true })); app.get('/media/audio/general/:path(*)', (req, res) => { const rel = decodeURIComponent(req.params.path || ''); diff --git a/station_broadcast.lua b/station_broadcast.lua index 2dd1ddc..5cc8b1d 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -1,6 +1,6 @@ -- 1. Configuration & Constants -local APP_VERSION_TEXT = "v1.0.102" +local APP_VERSION_TEXT = "v1.0.103" local CONFIG = { CLOUD_URL = "ws://stabadmin.fse-media.group",