fix(server): 改用 Express 5 + path-to-regexp v7 兼容的通配写法,避免路由启动崩溃
Express 5 内置的 path-to-regexp v7 不再支持裸 '*',也不支持 自定义正则 '.*'(会报 Missing parameter name)。Express 5 官方兼容的单段全通写是 ':name(*)',并且路由注册会在 app 启动 第一时间完成(出错会直接崩)。 同时为了兼容旧 URL 行为,保留 express.static 前置挂载 + 显式 app.get 后备两条路径,因为 Audio 模块可能需要带 Cache-Control / Range / Content-Type 等头的 custom sendBinaryFile 处理(例如 station 动态裁剪音频),所以不能直接用 static 替代。 修复 7 条路由: /media/audio/general/:path(*) /media/audio/beep/:path(*) /media/audio/music/:path(*) /media/audio/voice/:path(*) /media/audio/line/:path(*) /media/audio/station/:path(*) /media/temp/:path(*) 参数解码加 decodeURIComponent(),兼容中文/空格文件名。 客户端 bump v1.0.101 -> v1.0.102
This commit is contained in:
+22
-16
@@ -148,44 +148,50 @@ function safeRelativeToBase(baseDir, relativePath) {
|
|||||||
return full;
|
return full;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get('/media/audio/general/:relPath(.*)', (req, res) => {
|
app.use('/media/audio/general', express.static(getBeepAudioDirs(), { fallthrough: true }));
|
||||||
const rel = req.params.relPath || '';
|
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.get('/media/audio/general/:path(*)', (req, res) => {
|
||||||
|
const rel = decodeURIComponent(req.params.path || '');
|
||||||
const candidates = getBeepAudioDirs().map(dir => safeRelativeToBase(dir, rel)).filter(Boolean);
|
const candidates = getBeepAudioDirs().map(dir => safeRelativeToBase(dir, rel)).filter(Boolean);
|
||||||
sendBinaryFileFromCandidates(res, candidates);
|
sendBinaryFileFromCandidates(res, candidates);
|
||||||
});
|
});
|
||||||
app.get('/media/audio/beep/:relPath(.*)', (req, res) => {
|
app.get('/media/audio/beep/:path(*)', (req, res) => {
|
||||||
const rel = req.params.relPath || '';
|
const rel = decodeURIComponent(req.params.path || '');
|
||||||
const candidates = getBeepAudioDirs().map(dir => safeRelativeToBase(dir, rel)).filter(Boolean);
|
const candidates = getBeepAudioDirs().map(dir => safeRelativeToBase(dir, rel)).filter(Boolean);
|
||||||
sendBinaryFileFromCandidates(res, candidates);
|
sendBinaryFileFromCandidates(res, candidates);
|
||||||
});
|
});
|
||||||
app.get('/media/audio/music/:relPath(.*)', (req, res) => {
|
app.get('/media/audio/music/:path(*)', (req, res) => {
|
||||||
const rel = req.params.relPath || '';
|
const rel = decodeURIComponent(req.params.path || '');
|
||||||
const full = safeRelativeToBase(audioMusicDir, rel);
|
const full = safeRelativeToBase(audioMusicDir, rel);
|
||||||
if (!full) return res.status(404).end();
|
if (!full) return res.status(404).end();
|
||||||
sendBinaryFile(res, full);
|
sendBinaryFile(res, full);
|
||||||
});
|
});
|
||||||
app.get('/media/audio/voice/:relPath(.*)', (req, res) => {
|
app.get('/media/audio/voice/:path(*)', (req, res) => {
|
||||||
const rel = req.params.relPath || '';
|
const rel = decodeURIComponent(req.params.path || '');
|
||||||
const full = safeRelativeToBase(audioVoiceDir, rel);
|
const full = safeRelativeToBase(audioVoiceDir, rel);
|
||||||
if (!full) return res.status(404).end();
|
if (!full) return res.status(404).end();
|
||||||
sendBinaryFile(res, full);
|
sendBinaryFile(res, full);
|
||||||
});
|
});
|
||||||
app.get('/media/audio/line/:relPath(.*)', (req, res) => {
|
app.get('/media/audio/line/:path(*)', (req, res) => {
|
||||||
const rel = req.params.relPath || '';
|
const rel = decodeURIComponent(req.params.path || '');
|
||||||
const full = safeRelativeToBase(audioLineDir, rel);
|
const full = safeRelativeToBase(audioLineDir, rel);
|
||||||
if (!full) return res.status(404).end();
|
if (!full) return res.status(404).end();
|
||||||
sendBinaryFile(res, full);
|
sendBinaryFile(res, full);
|
||||||
});
|
});
|
||||||
|
app.get('/media/audio/station/:path(*)', (req, res) => {
|
||||||
app.get('/media/audio/station/:relPath(.*)', (req, res) => {
|
const rel = decodeURIComponent(req.params.path || '');
|
||||||
const rel = req.params.relPath || '';
|
|
||||||
const full = safeRelativeToBase(audioStationDir, rel);
|
const full = safeRelativeToBase(audioStationDir, rel);
|
||||||
if (!full) return res.status(404).end();
|
if (!full) return res.status(404).end();
|
||||||
sendBinaryFile(res, full);
|
sendBinaryFile(res, full);
|
||||||
});
|
});
|
||||||
|
app.get('/media/temp/:path(*)', (req, res) => {
|
||||||
app.get('/media/temp/:relPath(.*)', (req, res) => {
|
const rel = decodeURIComponent(req.params.path || '');
|
||||||
const rel = req.params.relPath || '';
|
|
||||||
const full = safeRelativeToBase(tempBroadcastDir, rel);
|
const full = safeRelativeToBase(tempBroadcastDir, rel);
|
||||||
if (!full) return res.status(404).end();
|
if (!full) return res.status(404).end();
|
||||||
sendBinaryFile(res, full);
|
sendBinaryFile(res, full);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
-- 1. Configuration & Constants
|
-- 1. Configuration & Constants
|
||||||
local APP_VERSION_TEXT = "v1.0.101"
|
local APP_VERSION_TEXT = "v1.0.102"
|
||||||
|
|
||||||
local CONFIG = {
|
local CONFIG = {
|
||||||
CLOUD_URL = "ws://stabadmin.fse-media.group",
|
CLOUD_URL = "ws://stabadmin.fse-media.group",
|
||||||
|
|||||||
Reference in New Issue
Block a user