fix(server): 彻底放弃 :path(*) 等参数化通配路由,改用 app.use + req.path 手动截取,解决 path-to-regexp v8.3 启动崩溃
服务器环境 path-to-regexp 实际版本是 8.3.0(Express 5.2.1 内置),
该版本既不接受裸 '*'、也不接受 ':name(.*)' 自定义正则、也不接受
':name(*)' 单段通配修饰符,参数路由只要带修饰符就会在 new Layer
阶段直接抛 PathError。
解决方案(这次本地用真实 node_modules 实装 require 整份 server.js
模拟启动,已确认不崩溃,http.createServer 正常被调用 3 次):
- 7 条 /media/* 路由全部删除 app.get('/prefix/:path(*)', ...)
- 改为 app.use('/prefix', middleware) + 在中间件里用 req.path
手动去掉前置 '/' 得到相对路径,再 decodeURIComponent();只处理
GET 请求,其他方法 next()
- static 命中优先(fallthrough),未命中时继续调用原
sendBinaryFile / sendBinaryFileFromCandidates 兜底,保持
Content-Type / Range / Accept-Ranges / Content-Length 等头
与旧行为完全一致
- 涉及:general / beep / music / voice / line / station / temp
客户端 bump v1.0.103 -> v1.0.104
This commit is contained in:
+49
-35
@@ -149,11 +149,16 @@ function safeRelativeToBase(baseDir, relativePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.use('/media/audio/general', (req, res, next) => {
|
app.use('/media/audio/general', (req, res, next) => {
|
||||||
|
if (req.method && String(req.method).toUpperCase() !== 'GET') return next();
|
||||||
const dirs = getBeepAudioDirs();
|
const dirs = getBeepAudioDirs();
|
||||||
if (!dirs || dirs.length === 0) return next();
|
const rel = decodeURIComponent(String(req.path || '/').replace(/^\/+/, ''));
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const tryNext = () => {
|
const tryNext = () => {
|
||||||
if (i >= dirs.length) return next();
|
if (i >= dirs.length) {
|
||||||
|
const candidates = (dirs || []).map(dir => safeRelativeToBase(dir, rel)).filter(Boolean);
|
||||||
|
if (candidates && candidates.length) return sendBinaryFileFromCandidates(res, candidates);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
const dir = String(dirs[i++] || '');
|
const dir = String(dirs[i++] || '');
|
||||||
if (!dir) return tryNext();
|
if (!dir) return tryNext();
|
||||||
express.static(dir, { fallthrough: true })(req, res, tryNext);
|
express.static(dir, { fallthrough: true })(req, res, tryNext);
|
||||||
@@ -161,63 +166,72 @@ app.use('/media/audio/general', (req, res, next) => {
|
|||||||
tryNext();
|
tryNext();
|
||||||
});
|
});
|
||||||
app.use('/media/audio/beep', (req, res, next) => {
|
app.use('/media/audio/beep', (req, res, next) => {
|
||||||
|
if (req.method && String(req.method).toUpperCase() !== 'GET') return next();
|
||||||
const dirs = getBeepAudioDirs();
|
const dirs = getBeepAudioDirs();
|
||||||
if (!dirs || dirs.length === 0) return next();
|
const rel = decodeURIComponent(String(req.path || '/').replace(/^\/+/, ''));
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const tryNext = () => {
|
const tryNext = () => {
|
||||||
if (i >= dirs.length) return next();
|
if (i >= dirs.length) {
|
||||||
|
const candidates = (dirs || []).map(dir => safeRelativeToBase(dir, rel)).filter(Boolean);
|
||||||
|
if (candidates && candidates.length) return sendBinaryFileFromCandidates(res, candidates);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
const dir = String(dirs[i++] || '');
|
const dir = String(dirs[i++] || '');
|
||||||
if (!dir) return tryNext();
|
if (!dir) return tryNext();
|
||||||
express.static(dir, { fallthrough: true })(req, res, tryNext);
|
express.static(dir, { fallthrough: true })(req, res, tryNext);
|
||||||
};
|
};
|
||||||
tryNext();
|
tryNext();
|
||||||
});
|
});
|
||||||
app.use('/media/audio/music', express.static(String(audioMusicDir || ''), { fallthrough: true }));
|
app.use('/media/audio/music', (req, res, next) => {
|
||||||
app.use('/media/audio/voice', express.static(String(audioVoiceDir || ''), { fallthrough: true }));
|
if (req.method && String(req.method).toUpperCase() !== 'GET') return next();
|
||||||
app.use('/media/audio/line', express.static(String(audioLineDir || ''), { fallthrough: true }));
|
const rel = decodeURIComponent(String(req.path || '/').replace(/^\/+/, ''));
|
||||||
app.use('/media/audio/station', express.static(String(audioStationDir || ''), { fallthrough: true }));
|
const base = String(audioMusicDir || '');
|
||||||
app.use('/media/temp', express.static(String(tempBroadcastDir || ''), { fallthrough: true }));
|
express.static(base, { fallthrough: true })(req, res, () => {
|
||||||
|
const full = base ? safeRelativeToBase(base, rel) : null;
|
||||||
app.get('/media/audio/general/:path(*)', (req, res) => {
|
|
||||||
const rel = decodeURIComponent(req.params.path || '');
|
|
||||||
const candidates = getBeepAudioDirs().map(dir => safeRelativeToBase(dir, rel)).filter(Boolean);
|
|
||||||
sendBinaryFileFromCandidates(res, candidates);
|
|
||||||
});
|
|
||||||
app.get('/media/audio/beep/:path(*)', (req, res) => {
|
|
||||||
const rel = decodeURIComponent(req.params.path || '');
|
|
||||||
const candidates = getBeepAudioDirs().map(dir => safeRelativeToBase(dir, rel)).filter(Boolean);
|
|
||||||
sendBinaryFileFromCandidates(res, candidates);
|
|
||||||
});
|
|
||||||
app.get('/media/audio/music/:path(*)', (req, res) => {
|
|
||||||
const rel = decodeURIComponent(req.params.path || '');
|
|
||||||
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/:path(*)', (req, res) => {
|
});
|
||||||
const rel = decodeURIComponent(req.params.path || '');
|
app.use('/media/audio/voice', (req, res, next) => {
|
||||||
const full = safeRelativeToBase(audioVoiceDir, rel);
|
if (req.method && String(req.method).toUpperCase() !== 'GET') return next();
|
||||||
|
const rel = decodeURIComponent(String(req.path || '/').replace(/^\/+/, ''));
|
||||||
|
const base = String(audioVoiceDir || '');
|
||||||
|
express.static(base, { fallthrough: true })(req, res, () => {
|
||||||
|
const full = base ? safeRelativeToBase(base, rel) : null;
|
||||||
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/:path(*)', (req, res) => {
|
});
|
||||||
const rel = decodeURIComponent(req.params.path || '');
|
app.use('/media/audio/line', (req, res, next) => {
|
||||||
const full = safeRelativeToBase(audioLineDir, rel);
|
if (req.method && String(req.method).toUpperCase() !== 'GET') return next();
|
||||||
|
const rel = decodeURIComponent(String(req.path || '/').replace(/^\/+/, ''));
|
||||||
|
const base = String(audioLineDir || '');
|
||||||
|
express.static(base, { fallthrough: true })(req, res, () => {
|
||||||
|
const full = base ? safeRelativeToBase(base, rel) : null;
|
||||||
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) => {
|
});
|
||||||
const rel = decodeURIComponent(req.params.path || '');
|
app.use('/media/audio/station', (req, res, next) => {
|
||||||
const full = safeRelativeToBase(audioStationDir, rel);
|
if (req.method && String(req.method).toUpperCase() !== 'GET') return next();
|
||||||
|
const rel = decodeURIComponent(String(req.path || '/').replace(/^\/+/, ''));
|
||||||
|
const base = String(audioStationDir || '');
|
||||||
|
express.static(base, { fallthrough: true })(req, res, () => {
|
||||||
|
const full = base ? safeRelativeToBase(base, rel) : null;
|
||||||
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) => {
|
});
|
||||||
const rel = decodeURIComponent(req.params.path || '');
|
app.use('/media/temp', (req, res, next) => {
|
||||||
const full = safeRelativeToBase(tempBroadcastDir, rel);
|
if (req.method && String(req.method).toUpperCase() !== 'GET') return next();
|
||||||
|
const rel = decodeURIComponent(String(req.path || '/').replace(/^\/+/, ''));
|
||||||
|
const base = String(tempBroadcastDir || '');
|
||||||
|
express.static(base, { fallthrough: true })(req, res, () => {
|
||||||
|
const full = base ? safeRelativeToBase(base, rel) : null;
|
||||||
if (!full) return res.status(404).end();
|
if (!full) return res.status(404).end();
|
||||||
sendBinaryFile(res, full);
|
sendBinaryFile(res, full);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/media', (req, res) => {
|
app.get('/media', (req, res) => {
|
||||||
res.json({
|
res.json({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
-- 1. Configuration & Constants
|
-- 1. Configuration & Constants
|
||||||
local APP_VERSION_TEXT = "v1.0.103"
|
local APP_VERSION_TEXT = "v1.0.104"
|
||||||
|
|
||||||
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