Upload files to Flask server via xhr

I’m trying to create a file upload using flask and forms, but it isn’t quite working. I can’t quite figure out where the issue is at all. I’ve tried following multiple tutorials and looked at many stack overflow threads to no avail.

It seems like Flask isn’t receiving any form data at all, and I can’t figure out why. Here’s my python code for the upload endpoint:

@app.route("/upload", methods=["post"])
def upload_endpoint():
    # Just prints ImmutableMultiDict([]) twice
    print(request.form)
    print(request.files)
    return "Success", 200

And here’s my js related to the uploading process:

// Creates and returns an input element with all needed tags and event listeners
function createInput() {
    const input = document.createElement("input")
    input.setAttribute("type", "file")
    input.setAttribute("multiple", "true")
    input.setAttribute("name", "file")

    input.addEventListener("change", () => {
        submitInput(input)
    }, false)

    return input
}

// Takes an input tag, puts it in a form, and submits it via xhr
function submitInput(input) {
    const form = document.createElement("form")
    form.appendChild(input)

    const xhr = new XMLHttpRequest()
    xhr.open("POST", "/upload")

    // Calculates and logs upload progress
    xhr.upload.addEventListener("progress", (e) => {
        const percent = e.lengthComputable ? (e.loaded / e.total) * 100 : 0
        console.log(percent.toFixed(2))
    })

    xhr.setRequestHeader("Content-Type", "multipart/form-data")
    xhr.send(new FormData(form))
}

// Handles for when element is clicked. .click() is used to create the popup dialogue for selecting a fike
centerDrop.addEventListener("click", () => {
    const input = createInput()
    input.click()
    return false
}, false)

// Handles for when a file is dropped into the browser
dropArea.addEventListener("drop", (e) => {
    const input = createInput()
    input.files = e.dataTransfer.files
    submitInput(input)
}, false)

I’ve been testing out the upload feature with a 200kb image, however the requests being created are <1kb in size according to the dev console in the browser. Why does the image seem to not be included in the request?

Answer

The problem is that I was trying to handle setting the request headers myself. Just removing this line: xhr.setRequestHeader("Content-Type", "multipart/form-data") did the trick for me.

Moral of the story is let XMLHttpRequest handle the headers for you, it knows what it’s doing already in the case of submitting form data.