70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import fs from 'fs/promises'
|
|
import path from 'path'
|
|
import env from '@/lib/env';
|
|
import resolveFilePath from '@/lib/file';
|
|
|
|
// 白名单:允许访问的文件扩展名
|
|
const allowedExtensions = ['.html', '.js', '.css', '.json', '.png', '.jpg', '.jpeg', '.gif', '.svg'];
|
|
|
|
const basePath = path.join(process.cwd(), env('STATIC_FILE_PATH'))
|
|
|
|
export async function GET(req: NextRequest,
|
|
{ params }: { params: Promise<{ path?: string[] }> }
|
|
) {
|
|
const fileseg = (await params).path
|
|
|
|
const filepath = resolveFilePath(fileseg, basePath, allowedExtensions, ['index.html'])
|
|
|
|
if (filepath === null) {
|
|
return NextResponse.json({ message: 'File not found' }, { status: 404 })
|
|
}
|
|
|
|
try {
|
|
// 获取文件扩展名以确定 MIME 类型
|
|
const extname = path.extname(filepath).toLowerCase();
|
|
if (!allowedExtensions.includes(extname)) {
|
|
return NextResponse.json({ error: 'Forbidden file type' }, { status: 403 });
|
|
}
|
|
// 设置响应头
|
|
let contentType = 'text/plain';
|
|
switch (extname) {
|
|
case '.html':
|
|
contentType = 'text/html';
|
|
break;
|
|
case '.js':
|
|
contentType = 'text/javascript';
|
|
break;
|
|
case '.css':
|
|
contentType = 'text/css';
|
|
break;
|
|
case '.json':
|
|
contentType = 'application/json';
|
|
break;
|
|
case '.png':
|
|
contentType = 'image/png';
|
|
break;
|
|
case '.jpg':
|
|
case '.jpeg':
|
|
contentType = 'image/jpeg';
|
|
break;
|
|
case '.gif':
|
|
contentType = 'image/gif';
|
|
break;
|
|
case '.svg':
|
|
contentType = 'image/svg+xml';
|
|
break;
|
|
default:
|
|
contentType = 'text/plain';
|
|
}
|
|
const responseHeaders = new Headers();
|
|
responseHeaders.set('Content-Type', contentType);
|
|
|
|
// 返回文件内容
|
|
return new NextResponse(await fs.readFile(filepath), { status: 200, headers: responseHeaders });
|
|
} catch (err) {
|
|
console.error(err);
|
|
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
|
}
|
|
}
|