Getting '400 Bad Request' when using multipart/form-data as Content-Type in XHR
Asked Answered
O

2

7

I have an AJAX request that sends out some data. The data respects the multipart/form-data specification.

The problem I'm facing is that the browser sets the Content-Type header to text/plain and it should be multipart/form-data.

I've tried doing this: request.setRequestHeader("Content-Type", "multipart/form-data"); but this gives out an 400 Bad Request error.

If I do request.setRequestHeader("Content-Typexxxx", "multipart/form-data"); there is no error, the "Content-Typexxxx" header is set but it obviously is no help to me.

I guess there is a list of valid Content-Type headers one can set and "multipart/form-data" isn't among them, but I cannot find a sollution to my predicament.

Sample of the data actually being sent:

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

--l3iPy71otz
Content-Disposition: form-data; name="titluPublic"

Variation_1
--l3iPy71otz
Content-Disposition: form-data; name="nr_versiune"


--l3iPy71otz--

Thanks!

Oily answered 23/1, 2011 at 12:10 Comment(2)
I think (hope) that How to create an AJAX request with JavaScript that contains both file and post data might be helpful. Otherwise, please post your code.Monopolist
I've read the documentation and I'm pretty sure the request is valid, I just can't set the Content-Type to multipart/form-data. Unfortunately the other post didn't shine any light on my problem.Oily
M
7

You didn't set the boundary in your request header, as in:

request.setRequestHeader("Content-Type", "multipart/form-data; boundary=l3iPy71otz");

For more information, see RFC 2045:

5 Content-Type Header Field
[…]
Parameters are modifiers of the media subtype, and as such do not fundamentally affect the nature of the content. The set of meaningful parameters depends on the media type and subtype. Most parameters are associated with a single specific subtype. However, a given top-level media type may define parameters which are applicable to any subtype of that type. Parameters may be required by their defining content type or subtype or they may be optional. MIME implementations must ignore any parameters whose names they do not recognize.

For example, the "charset" parameter is applicable to any subtype of "text", while the "boundary" parameter is required for any subtype of the "multipart" media type.

Update: Another problem I found on the net appears when a charset is added to the Content-type in the request header, but not in the message boundaries in the body (this is also true for your test case). It doesn't seem a likely solution, but perhaps it helps.

In your case, explicitly add a charset to both the request header and in the message boundaries:

data.params += "--" + data.uniqid + "; charset=UTF-8" + data.crlf;
…
request.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + data.uniqid + "; charset=UTF-8");

Update 2: After trying this myself locally, I noticed the leading boundary wasn't recognized as such, but interpreted as the last parameter contents (on my more forgiving server). Perhaps that was causing Apache to throw a 400 Bad Request error.

After some trial and error, I noticed that that was caused because the server expected the charset to be in every boundary, even the last one. To prevent confusion, I decided to explicitly set the charset in the request header before the boundary parameter, so that the boundary would be the last parameter in the Content-type request header. After this, everything seemed to work fine.

data.params = "Content-Type: multipart/form-data; boundary=" + data.uniqid;
…
data.params += "--" + data.uniqid + data.crlf;
…
data.params += "--" + data.uniqid + "--";
…
request.setRequestHeader("Content-Type", "multipart/form-data; charset=UTF-8; boundary=" + data.uniqid);
Monopolist answered 23/1, 2011 at 12:54 Comment(13)
the actual code is here. just press the first action button (not the delete one :) ) and you'll see page I'm working on. If you submit the form (bottom of the page) you'll get the actual 400 error. The javascript file is here - I've commented near the part that generates the bad request error. Thanks a lot!!!!!Oily
@Sorin: Why do you explicitly set the Content-length to 8000? AFAIK, you really shouldn't do that.Monopolist
@Marcel Korpel: I was just trying out different solutions. I took it out.Oily
@Marcel: I added the charset, but it's still not working. I'm fairly new to javascript and ajax so you can immagine how frustrating this must be ..Oily
@Marcel: just [23/Jan/2011:01:13:53 +0200] "POST /florin2/request.php?action=produsUpdate&id=24556 HTTP/1.1" 404 - "http://clienti.bsorin.ro/florin2/cautare" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13"Oily
@Sorin: Now I see a 404, that's probably related to the unfound ErrorDocument; is there also a 400 error present? BTW, you're doing a POST request and you're sending URL parameters; though not technically wrong, there might be some problem with Apache/PHP. Can you try to omit the URL parameters and see if you get any $_POST variables in your server side script?Monopolist
@Marcel: 400 error: [Sun Jan 23 16:35:05 2011] [error] File does not exist: /home/soinro/!!clienti/400.shtml, referer: http://clienti.bsorin.ro/florin2/cautare. I also left out the URL parameters, but this doesn't change anythingOily
@Sorin: No, this isn't the line regarding the 400 error, but the line regarding the 404 error. BTW, why are you using multipart/form-data anyway, instead of sticking to the default application/x-www-form-urlencoded for form data, where it is much easier to construct the POST data (only don't forget to use encodeURIComponent).Monopolist
@Marcel: There are no other references to 400 errors. The script will have to support sending all sorts of data, not just text like it currently does.Oily
@Sorin: In that case, can you post your server side code, so I (and other people here) can test this locally myself.Monopolist
@Marcel: request.php is just echo '$_SERVER[CONTENT_TYPE]='.$_SERVER['CONTENT_TYPE'].'<br /><br />'; echo '<pre>'.file_get_contents('php://input').'</pre>'; debug($_POST); where debug() is just a nicer var_dump();Oily
@Marcel: Thanks for all the patience and support you've put into this. As it seems we couldn't figure out a solution I'll switch to the x-www-form-urlencode solution for now as I have to finish this job. Maybe at some point I'll get back to figuring this out and if I do I'll be sure to post the solution here. Thanks again!Oily
@Sorin: So my last update (#2) didn't solve your problem? Too bad... Anyway, you're welcome.Monopolist
B
0

In case anyone else comes across this post: I ran into the same problem as described by the OP here, but in the context of a Springboot Java project. After some investigation, it turned out the issue was a missing Multipart config in the Servlet registration that was used under the hood by the embedded Jetty's servlet context initializer. So, the solution was simply to add this config during the registration of the dispatcher servlet, like this:

[...]
DispatcherServlet dispatcherServlet = new DispatcherServlet(webApplicationContext);
ServletRegistration.Dynamic registration = 
servletContext.addServlet(SERVLET_NAME, dispatcherServlet);
MultipartConfigElement multiPartConfig = new MultipartConfigElement(getSomeDirectory());
registration.setMultipartConfig(multiPartConfig);
[...]

HTH.

Babylon answered 22/4 at 8:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.