When you make a POST request, you have to encode the data that forms the body of the request in some way.
HTML forms provide three methods of encoding.
application/x-www-form-urlencoded
(the default)
multipart/form-data
text/plain
Work was being done on adding application/json
, but that has been abandoned.
(Other encodings are possible with HTTP requests generated using other means than an HTML form submission. JSON is a common format for use with web services and some still use SOAP.)
The specifics of the formats don't matter to most developers. The important points are:
When you are writing client-side code:
- use
multipart/form-data
when your form includes any <input type="file">
elements
- otherwise you can use
multipart/form-data
or application/x-www-form-urlencoded
but application/x-www-form-urlencoded
will be more efficient
When you are writing server-side code:
- Use a prewritten form handling library
Most (such as Perl's CGI->param
or the one exposed by PHP's $_POST
superglobal) will take care of the differences for you. Don't bother trying to parse the raw input received by the server.
Sometimes you will find a library that can't handle both formats. Node.js's most popular library for handling form data is body-parser which cannot handle multipart requests (but has documentation that recommends some alternatives which can).
If you are writing (or debugging) a library for parsing or generating the raw data, then you need to start worrying about the format. You might also want to know about it for interest's sake.
application/x-www-form-urlencoded
is more or less the same as a query string on the end of the URL.
multipart/form-data
is significantly more complicated but it allows entire files to be included in the data. An example of the result can be found in the HTML 4 specification.
text/plain
is introduced by HTML 5 and is useful only for debugging — from the spec: They are not reliably interpretable by computer — and I'd argue that the others combined with tools (like the Network Panel in the developer tools of most browsers) are better for that).
Starting with Safari 5/Firefox 4, it’s easiest to use the FormData
class:
var data = new FormData();
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file-'+i, file);
});
So now you have a FormData
object, ready to be sent along with the XMLHttpRequest.
jQuery.ajax({
url: 'php/upload.php',
data: data,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data){
alert(data);
}
});
It’s imperative that you set the contentType
option to false
, forcing jQuery not to add a Content-Type
header for you, otherwise, the boundary string will be missing from it.
Also, you must leave the processData
flag set to false, otherwise, jQuery will try to convert your FormData
into a string, which will fail.
You may now retrieve the file in PHP using:
$_FILES['file-0']
(There is only one file, file-0
, unless you specified the multiple
attribute on your file input, in which case, the numbers will increment with each file.)
Using the FormData emulation for older browsers
var opts = {
url: 'php/upload.php',
data: data,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data){
alert(data);
}
};
if(data.fake) {
// Make sure no text encoding stuff is done by xhr
opts.xhr = function() { var xhr = jQuery.ajaxSettings.xhr(); xhr.send = xhr.sendAsBinary; return xhr; }
opts.contentType = "multipart/form-data; boundary="+data.boundary;
opts.data = data.toString();
}
jQuery.ajax(opts);
Create FormData from an existing form
Instead of manually iterating the files, the FormData object can also be created with the contents of an existing form object:
var data = new FormData(jQuery('form')[0]);
Use a PHP native array instead of a counter
Just name your file elements the same and end the name in brackets:
jQuery.each(jQuery('#file')[0].files, function(i, file) {
data.append('file[]', file);
});
$_FILES['file']
will then be an array containing the file upload fields for every file uploaded. I actually recommend this over my initial solution as it’s simpler to iterate over.
Best Answer
Seems like I found the solution on my own.
First, the link that helped me a lot : http://www.ioncannon.net/programming/975/spring-3-file-upload-example/ and Spring 3 MVC - form:errors not showing the errors which showed a good trick to display all errors, using
Now, a list of all the things i changed to make that thing work :
1/ use "rejectValue" instead of "reject".
2/ return the view directly instead of a redirect.
3/ create a "UploadItem" model with a CommonsMultipartFile property
So, all in all, my controller method became
Hope that helped.