6

In python I send files like this:

with open('D:\\someimage.jpg', 'rb') as image:
imager = image.read()
files = {'image': imager}
r = requests.post(url, files=files)

I want to do similar thing in js, but I always get 400 Bad Request error. The problem, I assume, is that I don't know what type the file should have. I've tried passing it in initial 'file' type, as array buffer, as binary string - nothing works. Here is my code:

var reader = new FileReader();
reader.readAsArrayBuffer(aFiles[0]);
reader.onload = function () {
var arrayBuffer = this.result,
array = new Uint8Array(arrayBuffer),
binaryString = String.fromCharCode.apply(null, array);
jQuery.ajax({
    url: '/streamer', 
    method: 'POST',
    files: {'image': binaryString},
    success: function(response) {
        alert(response);
    },
    error: function(xhr, status, error) {
       alert(JSON.parse(xhr.responseText));
    }});
Liam
  • 27,717
  • 28
  • 128
  • 190
Chris Gabler
  • 179
  • 1
  • 1
  • 14
  • 1
    Possible duplicate of [jQuery Ajax File Upload](https://stackoverflow.com/questions/2320069/jquery-ajax-file-upload) – Liam Aug 06 '18 at 10:43

1 Answers1

7

You can send the file as a FormData (multipart/form-data) if you need to send more fields or as a Blob if you just want to send the binary directly.

jQuery tries to be smart about processing the data you send. But jQuery don't understand FormData or blobs, it sees it as an object and do the wrong thing. that's why you need to set processData = false and don't set the wrong request content-type by doing contentType = false and just let the xhr do that itself.

var fd = new FormData();
fd.append('image', aFiles[0] /*, optional filename */)

var req = jQuery.ajax({
  url: '/streamer', 
  method: 'POST',
  data: fd, // sends fields with filename mimetype etc
  // data: aFiles[0], // optional just sends the binary
  processData: false, // don't let jquery process the data
  contentType: false // let xhr set the content type
});

// jQuery is promise A++ compatible and is the todays norms of doing things 
req.then(function(response) {
  console.log(response)
}, function(xhr) {
  console.error('failed to fetch xhr', xhr)
})

But you don't really need jQuery for this things if you only support the latest browser that has the fetch api

var req = fetch('/streamer', {
  method: 'post',
  body: fd /* or aFile[0]*/
}); // returns a promise

req.then(function(response) {
  // returns status + response headers
  // but not yet the body, 
  // for that call `response[text() || json() || arrayBuffer()]` <-- also promise

  if (res.ok) {
    // status code was 200-299
  } else {
    // status was something else
  }
}, function(error) {
  console.error('failed due to network error or cross domain')
})
Endless
  • 34,080
  • 13
  • 108
  • 131