fix(server): 修复 serve-static 不接受数组 root、改为按请求逐个挂载,避免启动时 TypeError: root path must be a string

上一轮把 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
This commit is contained in:
2026-08-17 15:44:38 +08:00
parent 5c462a4d09
commit a6d9b6c418
2 changed files with 30 additions and 8 deletions
+29 -7
View File
@@ -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 || '');
+1 -1
View File
@@ -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",