sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
18.47k stars 1.89k forks source link

Fail to POST PDF multipart formdata from server on localhost #11955

Open andreapiso opened 6 months ago

andreapiso commented 6 months ago

Describe the bug

Somehow, suddenly I am not able to send PDF files via POST to external APIs when running on localhost.

However, if I deploy this code on Vercel, it works fine - it only hangs on localhost. What could be going wrong here?

Reproduction

I have set up something simple to replicate:

I have a simple file upload button:

<script lang="ts">
    let files: FileList;
    let uploading = false;

    async function uploadFiles() {
        uploading = true;
        const result = await uploadFile(files[0]);
        uploading = false;
        console.log(result);
    }

    async function uploadFile(uploadedFile: File) {

        const formData = new FormData();
        formData.append('file', uploadedFile);

        try {
            const response = await fetch('/api/one', {
                method: 'POST',
                body: formData
            });

            if (!response.ok) {
                throw new Error('Error connecting');
            }

            const data = await response.json();
            return data;
        } catch (error: any) {
            console.error('Error in chunkFile:', error);
            return { error: error.message }; // or return a string like 'Error connecting'
        } 
    }
</script>

{#if uploading}
    Uploading...
{:else}
    <div class="grid w-5 max-w-sm items-center gap-1.5">
        <label class="cursor-pointer" for="many">"Upload"</label>
        <input bind:files on:change={uploadFiles} id="many" multiple type="file" class="hidden" />
    </div>
{/if}

{#if files}
    <h2>Selected files:</h2>
    {#each Array.from(files) as file}
        <p>{file.name} ({file.size} bytes)</p>
    {/each}
{/if}

Which posts the PDF to an endpoint /api/one

This endpoint simply takes the FormData and re-posts it to another endpoint (just to replicate the issue)

import { json } from '@sveltejs/kit';

export const POST = async ({ request, fetch }) => {
    const requestBody = await request.formData();
    const requestFile = requestBody.get('file');
    console.log(requestFile);

    if (requestFile === null) {
        return json({ error: 'File is missing' }, { status: 400 });
    }

    if (!(requestFile instanceof Blob)) {
        return json({ error: 'Invalid file type' }, { status: 400 });
    }
    console.log('Start Fetch');
    const formData = new FormData();
    formData.append('file', requestFile);
    const response = await fetch(`/api/two`, {
        method: 'POST',
        body: formData
    });
    console.log('End Fetch');
    if (response.ok) {
        const data = await response.json();
        return json(data);
    } else if (response.status >= 400 && response.status < 600) {
        console.error(`Received HTTP ${response.status}. Retrying...`);
    } else {
        const errorText = await response.text();
        console.error(`Received HTTP ${response.status}. Not retrying.`);
        console.error(errorText);
        return json(
            { error: `Received HTTP ${response.status}. Error message: ${errorText}` },
            { status: response.status }
        );
    }
};

The second endpoint hangs on event.request.formData().

import { json } from '@sveltejs/kit';

export const POST = async (event) => {
    console.log('Received request');
    const requestBody = await event.request.formData();
    const requestFile = requestBody.get('file');
    console.log(requestFile);

    if (requestFile === null) {
        return json({ error: 'File is missing' }, { status: 400 });
    }

    if (!(requestFile instanceof Blob)) {
        return json({ error: 'Invalid file type' }, { status: 400 });
    }

    console.log(requestFile);
    return json({ message: 'Success.' }, { status: 200 });
};

POSTing to other external endpoints like Python FastAPI causes the same issue.

Logs

No response

System Info

MacOS

Severity

blocking all usage of SvelteKit

Additional Information

No response

ICTVTS3 commented 6 months ago

I'm experiencing the same issue. The code is very similar as well. The PDF files for testing in my case are very small, but either take a long time to send to my API or hang. I tried sending the file after converting to base64, which worked almost instantaneous.

karimfromjordan commented 6 months ago

@andreapiso Can you share a minimal repo?

andreapiso commented 6 months ago

@karimfromjordan here is a minimal repo: https://github.com/andreapiso/minimal-pdf-post

I discovered that the bug is linked to the node version. The repo above hangs on node 20.4.0 but works on node 21.7.0 and 18.16.1

moatra commented 6 months ago

Probably related: #11126

tichmajena commented 6 months ago

I was having a similar issue, it got resolved after I add enctype="multipart/form-data" to the form element : <form enctype="multipart/form-data" action="?/upload" method="post" ></form>

andreapiso commented 1 week ago

@tichmajena probably not the same issue - this one only got solved by updating the node version - there's reason to believe there are still combinations of sveltekit and node which have a broken POST.