1

I am transitioning from http.server to Flask. My image upload using AJAX is now broken. This is running Python 3.

Troubleshooting that did not work:

  • I have included multipart/form-data in the Ajax request.

  • I have tried to have a shared and dedicated route for the upload.

  • I have added @cross_origin() it solved the problem for a similar question.

  • I tried looking in other request dicts, nothing contains anything.

  • I originally ran the app on 0.0.0.0, so changed that to 127.0.0.1.

  • I tried to add an entire form to the FormData and just the image. I am reluctant to change much more of the Ajax since it works on http.server.

  • Tried both sync and async AJAX requests.

No matter what I attempt I always get the same result:

print(request.files) returns ImmutableMultiDict([])

I'ld rather avoid using JQuery, as this should work since it works on http.server.

Relevant code:

Non-working Flask:

@app.route("/qr_upload", methods=["GET", "POST"])
@cross_origin()
def receive_image():
  if (request.method == "POST"):
    print("qr_code" in request.files)  # This always returns False.
    multipart_data = request.files["qr_code"]

  return "Post"


if __name__ == "__main__":
  app.run("127.0.0.1", PORT, True)

Working AJAX on http.server


    // Add the image to the request and send it.
    var formData = new FormData(document.getElementById("qrPickerForm"))

    xhttp.open("POST", "/qr_upload")
    xhttp.setRequestHeader("Content-Type", "multipart/form-data")
    xhttp.send(formData)

Related HTML

<form action = "/qr_upload" id = "qrPickerForm" name = "qr_form" method="post" enctype = "multipart/form-data">
    <input id = "qrFilePicker" name = "qr_code" type = "file" accept="image/*" capture="camera">
    <input type="submit">
</form>

Working http.server:

 def do_POST(self):
    # Extract the multiform data from the POST request
    cLen = int(self.headers["Content-Length"])
    body = self.rfile.read(cLen)

    # Decode the multiform data and get the image bytes.
    multipart_data = decoder.MultipartDecoder(body, "multipart/form-data; boundary=WebKitFormBoundary")

    # This and Flask's code should have the same data here.

Handler = S
with socketserver.TCPServer(("", PORT-1), Handler) as httpd:
  httpd.serve_forever()

Update 1:

It works if I send the image with a form's submit button, but not with AJAX. Have not figured out why yet though.

Fivreld
  • 41
  • 6
  • Possible duplicate of [Getting an empty ImmutableMultiDict object from jQuery request data](https://stackoverflow.com/questions/36995516/getting-an-empty-immutablemultidict-object-from-jquery-request-data) – Kate Orlova Jun 23 '19 at 23:04
  • @KateOrlova I'm not running JQuery though? – Fivreld Jun 23 '19 at 23:10
  • Ok, @Fivreld. Does your form have `enctype="multipart/form-data"` attribute? I hope it does otherwise **files** will be empty. – Kate Orlova Jun 23 '19 at 23:26
  • @KateOrlova Shouldn't this `xhttp.setRequestHeader("Content-Type", "multipart/form-data")` be enough? – Fivreld Jun 23 '19 at 23:33
  • No, it is not. That should be specified for your `
    ` tag in HTML view, please check your form definition.
    – Kate Orlova Jun 24 '19 at 12:51
  • @KateOrlova I've found a solution. See my dedicated answer for details. – Fivreld Jun 24 '19 at 14:29

1 Answers1

3

I dug around a little bit in Wireshark since it seemed weird to me that it worked on one HTTP server but not another.

This is the Content-Type of the request to http.server and when using the submit button: Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryLiIs2nrWOjrabtB1

This is the Content-Type of the broken request: Content-Type: multipart/form-data

So it seems like setting a Content-Type directly with xhttp.setRequestHeader("Content-Type", "multipart/form-data")was a bad idea, presumably as it overwrites the enctype set in the , but without the boundary.

I removed the line and it now works as intended.

Fivreld
  • 41
  • 6