fix: use preview-mode signed URLs and graceful media preview fallback

This commit is contained in:
2026-02-17 19:36:49 +08:00
parent 2b700978ad
commit f0e7381c1d
3 changed files with 58 additions and 8 deletions

View File

@@ -686,6 +686,30 @@ function getBusyDownloadMessage() {
return '当前网络繁忙,请稍后再试';
}
function getPreviewContentTypeByPath(filePath = '') {
const ext = path.extname(String(filePath || '')).toLowerCase();
const map = {
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.bmp': 'image/bmp',
'.webp': 'image/webp',
'.svg': 'image/svg+xml',
'.mp4': 'video/mp4',
'.mov': 'video/quicktime',
'.webm': 'video/webm',
'.mkv': 'video/x-matroska',
'.mp3': 'audio/mpeg',
'.wav': 'audio/wav',
'.flac': 'audio/flac',
'.ogg': 'audio/ogg',
'.m4a': 'audio/mp4',
'.aac': 'audio/aac'
};
return map[ext] || '';
}
function parseDateTimeValue(value) {
if (!value || typeof value !== 'string') {
return null;
@@ -4534,6 +4558,8 @@ app.post('/api/files/upload-complete', authMiddleware, async (req, res) => {
// 生成 OSS 下载签名 URL用户直连 OSS 下载,不经过后端)
app.get('/api/files/download-url', authMiddleware, async (req, res) => {
const filePath = req.query.path;
const mode = String(req.query.mode || 'download').toLowerCase();
const isPreviewMode = mode === 'preview';
if (!filePath) {
return res.status(400).json({
@@ -4610,12 +4636,22 @@ app.get('/api/files/download-url', authMiddleware, async (req, res) => {
}
}
// 创建 GetObject 命令
const command = new GetObjectCommand({
// 创建 GetObject 命令(预览模式使用 inline下载模式使用 attachment
const fileName = normalizedPath.split('/').pop() || 'download.bin';
const commandInput = {
Bucket: bucket,
Key: objectKey,
ResponseContentDisposition: `attachment; filename="${encodeURIComponent(normalizedPath.split('/').pop())}"`
});
ResponseContentDisposition: isPreviewMode
? `inline; filename*=UTF-8''${encodeURIComponent(fileName)}`
: `attachment; filename*=UTF-8''${encodeURIComponent(fileName)}`
};
if (isPreviewMode) {
const previewContentType = getPreviewContentTypeByPath(fileName);
if (previewContentType) {
commandInput.ResponseContentType = previewContentType;
}
}
const command = new GetObjectCommand(commandInput);
// 生成签名 URL1小时有效
const signedUrl = await getSignedUrl(client, command, { expiresIn: 3600 });