fix(pdf-compress): use arrayBuffer() instead of formData() for large files
formData() fails with "Failed to parse body as FormData" on large PDFs in Next.js route handlers. Switch to req.arrayBuffer() which reliably reads the full body, then manually extract the PDF from multipart. Extreme mode: arrayBuffer + multipart extraction + GS + qpdf pipeline. Stirling mode: arrayBuffer forwarding to Stirling with proper headers. Revert serverActions.bodySizeLimit (doesn't apply to route handlers). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,41 +7,22 @@ const STIRLING_PDF_API_KEY =
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
// Parse incoming form data — get file + optimizeLevel
|
||||
let formData: FormData;
|
||||
try {
|
||||
formData = await req.formData();
|
||||
} catch (parseErr) {
|
||||
const msg =
|
||||
parseErr instanceof Error ? parseErr.message : "Parse error";
|
||||
return NextResponse.json(
|
||||
{ error: `Nu s-a putut citi formularul: ${msg}` },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
// Buffer the full body then forward to Stirling — streaming passthrough
|
||||
// (req.body + duplex:half) is unreliable for large files in Next.js.
|
||||
const bodyBytes = await req.arrayBuffer();
|
||||
const contentType = req.headers.get("content-type") || "";
|
||||
|
||||
const fileField = formData.get("fileInput");
|
||||
if (!fileField || !(fileField instanceof Blob)) {
|
||||
return NextResponse.json(
|
||||
{ error: "Lipsește fișierul PDF." },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const optimizeLevel = formData.get("optimizeLevel") ?? "3";
|
||||
const originalSize = fileField.size;
|
||||
|
||||
// Build fresh FormData for Stirling
|
||||
const stirlingForm = new FormData();
|
||||
stirlingForm.append("fileInput", fileField, "input.pdf");
|
||||
stirlingForm.append("optimizeLevel", String(optimizeLevel));
|
||||
// Extract original file size from the multipart body for the response header
|
||||
// (rough estimate — the overhead of multipart framing is negligible for large PDFs)
|
||||
const originalSize = bodyBytes.byteLength;
|
||||
|
||||
const res = await fetch(`${STIRLING_PDF_URL}/api/v1/misc/compress-pdf`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-API-KEY": STIRLING_PDF_API_KEY,
|
||||
"Content-Type": contentType,
|
||||
},
|
||||
body: stirlingForm,
|
||||
body: bodyBytes,
|
||||
signal: AbortSignal.timeout(300_000), // 5 min for large files
|
||||
});
|
||||
|
||||
@@ -56,7 +37,7 @@ export async function POST(req: NextRequest) {
|
||||
const blob = await res.blob();
|
||||
const buffer = Buffer.from(await blob.arrayBuffer());
|
||||
|
||||
return new NextResponse(buffer, {
|
||||
return new NextResponse(new Uint8Array(buffer), {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/pdf",
|
||||
|
||||
Reference in New Issue
Block a user