44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
import { createReadStream, statSync } from 'node:fs'
|
|
import { resolve, sep } from 'node:path'
|
|
|
|
const contentTypes: Record<string, string> = {
|
|
jpg: 'image/jpeg',
|
|
jpeg: 'image/jpeg',
|
|
png: 'image/png',
|
|
webp: 'image/webp',
|
|
}
|
|
|
|
export default defineEventHandler((event) => {
|
|
const requested = getRouterParam(event, 'path') || ''
|
|
const uploadsRoot = resolve(process.cwd(), 'data', 'uploads')
|
|
const legacyRoot = resolve(process.cwd(), 'data', 'media')
|
|
let mediaRoot = uploadsRoot
|
|
let filePath = resolve(mediaRoot, requested)
|
|
if (!filePath.startsWith(`${mediaRoot}${sep}`)) {
|
|
throw createError({ statusCode: 400, statusMessage: '无效的文件路径' })
|
|
}
|
|
|
|
let fileStat
|
|
try {
|
|
fileStat = statSync(filePath)
|
|
} catch {
|
|
const legacyPath = resolve(legacyRoot, requested)
|
|
if (!legacyPath.startsWith(`${legacyRoot}${sep}`)) throw createError({ statusCode: 400, statusMessage: '无效的文件路径' })
|
|
try { fileStat = statSync(legacyPath); filePath = legacyPath; mediaRoot = legacyRoot }
|
|
catch { throw createError({ statusCode: 404, statusMessage: '图片不存在' }) }
|
|
}
|
|
if (!fileStat.isFile()) {
|
|
throw createError({ statusCode: 404, statusMessage: '图片不存在' })
|
|
}
|
|
|
|
const extension = filePath.split('.').pop()?.toLowerCase() || ''
|
|
const contentType = contentTypes[extension]
|
|
if (!contentType) {
|
|
throw createError({ statusCode: 415, statusMessage: '不支持的文件类型' })
|
|
}
|
|
setHeader(event, 'Content-Type', contentType)
|
|
setHeader(event, 'Content-Length', fileStat.size)
|
|
setHeader(event, 'Cache-Control', 'public, max-age=31536000, immutable')
|
|
return sendStream(event, createReadStream(filePath))
|
|
})
|