0

I'm using nginx to serve a page which contains a form for uploading files to the server. I'm using the FormData() class as my data in the POST request:

js:

$.ajax({
   url: /upload,
   type: 'POST',
   data: formData,
   async: false,
   cache: false,
   contentType: false,
   enctype: 'multipart/form-data',
   processData: false,
   success: function (response) {
     alert(response);
   }
});

I'm using the example nginx upload module, using the default configuration at the bottom of this page: https://www.nginx.com/resources/wiki/modules/upload/:

location /upload {
    # Pass altered request body to this location
    upload_pass   @test;

    # Store files to this directory
    # The directory is hashed, subdirectories 0 1 2 3 4 5 6 7 8 9 should exist
    upload_store /tmp 1;

    # Allow uploaded files to be read only by user
    upload_store_access user:r;

    # Set specified fields in request body
    upload_set_form_field $upload_field_name.name "$upload_file_name";
    upload_set_form_field $upload_field_name.content_type "$upload_content_type";
    upload_set_form_field $upload_field_name.path "$upload_tmp_path";

    # Inform backend about hash and size of a file
    upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
    upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";

    upload_pass_form_field "^submit$|^description$";

    upload_cleanup 400 404 499 500-505;
}

# Pass altered request body to a backend
location @test {
    proxy_pass   http://localhost:8080;
}

I'm not using any PHP scripts or whatever; I was under the impression that the default upload module configuration would just dump the uploaded file to /tmp/1 (I have created this directory and given write permissions to nginx). The file is only a few kb so there should be no issues with file size.

When I try and upload a file, I get a HTTP 415 error i.e. Unsupported Media Type. The file I'm uploading has an extension .bin, which is a supported MIME type in the /etc/nginx/mime.types file.

I can issue a similar request on the command line using cURL:

curl -F 'file@=myfile.bin' http://<URL>/upload

and this works fine. Inspecting the output of curl, I see that in the POST header

Content-Type: multipart/form-data; boundary=-------etc

but this is disabled in the jQuery ajax call above as

Content-Type: false;

as recommended in SO posts like How can I upload files asynchronously? . If I force the Content-Type in the ajax call to multipart/form-data, I get a 400 Bad Request error. Can someone explain where I'm going wrong?

user12066
  • 613
  • 6
  • 23

1 Answers1

0

So it seems that when POSTing form data using a FormData class, the jquery ajax POST method will pass

Content-Type: false

right to the backend server, in this case nginx. This content type is not recognised nginx, hence the 415 error. I couldn't find a straightforward answer to get around this problem, so I had to resort to a simple XMLHTTPRequest:

var form = document.getElementById("MyFormId");

var req = new XMLHTTPRequest();
req.open('POST', url, true);

req.onprogress = function () {
    // handle progress
}

req.onload = function () {
    // successful request
}

req.onerror= function () {
    // request in error
}

req.send(new FormData(form));
event.preventDefault();

When I send this, the form data makes its way to nginx intact and in the HTTP request

Content-Type: 'multipart/form-data'

exactly as I saw using cURL.

I hope this is of use to someone.

user12066
  • 613
  • 6
  • 23