54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
import { NextResponse, type NextRequest } from "next/server";
|
|
import { requireApiUser } from "@/lib/api-auth";
|
|
import { getStoredImageAssetForViewer } from "@/lib/db";
|
|
import { jsonError, normalizeError } from "@/lib/http";
|
|
import { readStoredImageFile } from "@/lib/image-storage";
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
export async function GET(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ id: string }> },
|
|
) {
|
|
try {
|
|
const viewer = requireApiUser(request);
|
|
const { id } = await params;
|
|
const asset = getStoredImageAssetForViewer({
|
|
viewerId: viewer.id,
|
|
viewerRole: viewer.role,
|
|
imageId: id,
|
|
});
|
|
|
|
if (!asset) {
|
|
return jsonError("图片不存在。", 404);
|
|
}
|
|
|
|
const fileBuffer = await readStoredImageFile(asset.storageKey);
|
|
const shouldDownload = request.nextUrl.searchParams.get("download") === "1";
|
|
const dispositionType = shouldDownload ? "attachment" : "inline";
|
|
|
|
return new NextResponse(new Uint8Array(fileBuffer), {
|
|
status: 200,
|
|
headers: {
|
|
"Content-Type": asset.mimeType,
|
|
"Content-Length": String(fileBuffer.byteLength),
|
|
"Cache-Control": "private, max-age=86400",
|
|
"Content-Disposition": `${dispositionType}; filename*=UTF-8''${encodeURIComponent(asset.fileName)}`,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
const normalizedError = normalizeError(error, "读取图片失败。");
|
|
|
|
if (
|
|
error &&
|
|
typeof error === "object" &&
|
|
"code" in error &&
|
|
error.code === "ENOENT"
|
|
) {
|
|
return jsonError("图片不存在。", 404);
|
|
}
|
|
|
|
return jsonError(normalizedError.message, normalizedError.statusCode);
|
|
}
|
|
}
|