fix: 安全处理报表下载文件名
This commit is contained in:
@@ -295,11 +295,45 @@ function parseContentDispositionFileName(value: string | null): string | undefin
|
|||||||
if (!value) return undefined
|
if (!value) return undefined
|
||||||
|
|
||||||
const utf8FileName = value.match(/filename\*=UTF-8''([^;]+)/i)
|
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]
|
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 中间态,
|
* 报表文件导出:使用 fetch + arrayBuffer,绕过 axios 拦截器与 Blob 中间态,
|
||||||
* 避免网络面板里已是合法 xlsx(PK…)但落盘文件损坏的情况。
|
* 避免网络面板里已是合法 xlsx(PK…)但落盘文件损坏的情况。
|
||||||
@@ -331,7 +365,11 @@ export const exportReport = async (
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
blob: exportBufferToBlob(ab, format, r.headers.get('content-type')),
|
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,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user