fix: 安全处理报表下载文件名

This commit is contained in:
zxr
2026-08-03 21:30:36 +08:00
parent 195aa7ccff
commit 3654ccb9db

View File

@@ -295,11 +295,45 @@ function parseContentDispositionFileName(value: string | null): string | undefin
if (!value) return undefined
const utf8FileName = value.match(/filename\*=UTF-8''([^;]+)/i)
if (utf8FileName) return decodeURIComponent(utf8FileName[1])
if (utf8FileName) {
try {
return decodeURIComponent(utf8FileName[1])
} catch {
// 编码异常时继续读取普通文件名
}
}
return value.match(/filename="([^"]+)"/i)?.[1]
}
function normalizeReportFileName(
fileName: string | undefined,
id: number,
format: ReportExportFormat,
): string {
const defaultName = `report_${id}.${format}`
if (!fileName) return defaultName
let name = fileName.split(/[\\/]/).pop() || ''
name = name
.replace(/[\u0000-\u001F\u007F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g, '')
.replace(/[<>:"/\\|?*]/g, '_')
.replace(/[ .]+$/, '')
const extensionIndex = name.lastIndexOf('.')
if (extensionIndex > 0) {
name = name.slice(0, extensionIndex).replace(/[ .]+$/, '')
}
if (!name) return defaultName
const reservedName = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i
if (reservedName.test(name.split('.')[0])) {
name = `_${name}`
}
return `${name}.${format}`
}
/**
* 报表文件导出:使用 fetch + arrayBuffer绕过 axios 拦截器与 Blob 中间态,
* 避免网络面板里已是合法 xlsxPK…但落盘文件损坏的情况。
@@ -331,7 +365,11 @@ export const exportReport = async (
}
return {
blob: exportBufferToBlob(ab, format, r.headers.get('content-type')),
fileName: parseContentDispositionFileName(r.headers.get('content-disposition')) || `report_${id}.${format}`,
fileName: normalizeReportFileName(
parseContentDispositionFileName(r.headers.get('content-disposition')),
id,
format,
),
}
}