27

Can I send a file as multipart by XMLHttpRequest to a servlet?

I am making a form and submitting it as multipart, but somehow I am not getting a response for successfully uploading it. I do not want the page to be refreshed, so it has to take place by Ajax.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tejasva Dhyani
  • 1,342
  • 1
  • 10
  • 19
  • See also: [Sending images from Canvas elements using Ajax and PHP $_FILES](http://stackoverflow.com/a/5303242/938089?sending-images-from-canvas-elements-using-ajax-and-php-files) – Rob W Feb 22 '12 at 15:02

2 Answers2

64

That's only possible with the XHR FormData API (previously known being part of as "XHR2" or "XHR Level 2", currently known as "XHR Advanced Features").

Given this HTML,

<input type="file" id="myFileField" name="myFile" />

you can upload it as below:

var formData = new FormData();
formData.append("myFile", document.getElementById("myFileField").files[0]);

var xhr = new XMLHttpRequest();
xhr.open("POST", "myServletUrl");
xhr.send(formData);

XHR will take care about proper headers and request body encoding and the file will in this example be available on the server side as form-data part with the name myFile.

You need to keep in mind that FormData API is not supported in older browsers. At caniuse.com you can see that it's currently implemented in Chrome 7+, Firefox 3.5+, Safari 5+, Internet Explorer 10+ and Opera 12+.

In case you're using jQuery, then you might be tempted to use its $.val() function as below:

formData.append("myFile", $("#myFileField").val());

But this is incorrect as it doesn't return the whole File object, but merely the file name as String which is utterly useless as it doesn't contain the file contents.

If you don't want to use document.getElementById() for some reason, then use one of the following instead:

formData.append("myFile", $("#myFileField").prop("files")[0]);
formData.append("myFile", $("#myFileField")[0].files[0]);

An alternative is to use the jQuery Form plugin. Your entire form, when written and functioning properly without any line of JavaScript code, will then instantly be ajaxified with just the following line:

$("#formId").ajaxForm(function(response) {
    // Handle Ajax response here.
});

It also supports file uploads as well by a hidden iframe trick. See also this jQuery Form documentation for an in-depth explanation. You may only need to change the servlet code to be able to intercept on both normal (synchronous) and Ajax (asynchronous) requests. See also this answer for a concrete example: Simple calculator with JSP/Servlet and Ajax

Either way, the uploaded file should then be available in the doPost() method of a @MultipartConfig servlet as follows:

Part myFile = request.getPart("myFile");

Or if you're still on Servlet 2.5 or older, use Apache Commons FileUpload the usual way. See also this answer for a concrete example: How can I upload files to a server using JSP/Servlet?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • And what happen if in our page we generate automatically many input files ? can we generate IDs ? – walox Jan 19 '17 at 19:30
  • @BalusC I'm wondering why there is no info about how & why XMLHttpRequest + FormData sets headers automatically, on MDN or other places (googled a lot). Whenever I set `Content-type', 'multipart/form-data'` my requests fail, but works if headers are not specified. But why? – Edmond Tamas Sep 27 '18 at 09:20
  • `XMLHttpRequest` works, but how to do the same with `axios`? – parsecer May 17 '23 at 12:26
  • Doesn't work in my case – catGPT Aug 02 '23 at 15:10
  • Click the 'Ask Question' button on right top to get answer on that. – BalusC Aug 02 '23 at 16:12
3

It's not possible to send multipart/form-data with XMLHttpRequest (though it is possible in modern browsers, with XHR2. See BalusC's answer).

A common way to achieve what you want is to use a regular form, but in an iframe instead. This way, only the iframe is refreshed on upload.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Linus Thiel
  • 38,647
  • 9
  • 109
  • 104
  • Actually I want a response whether the file is uploaded or not. Also, I want the location where the image is uploaded. – Tejasva Dhyani Feb 22 '12 at 14:29
  • Tejasva: Look at the example from Napolux, it specifies how you can call a js function on the parent window when upload is complete. It could provide the image location as well. – Linus Thiel Feb 22 '12 at 14:38
  • @LinusGThiel It is possible. See BalusC's answer. – Šime Vidas Feb 22 '12 at 15:10
  • Yes, it's possible with XHR2. With modern browsers, there is also FileAPI and other cool features. Perhaps I should try to explain how to accomplish this, with fallbacks for older browsers, etc. Honestly, I wasn't sure I would get that across in a good manner to the asker. I agree that BalusC's answer is better than mine. – Linus Thiel Feb 22 '12 at 15:24