-
-
Save getify/3167492 to your computer and use it in GitHub Desktop.
| var xhr, form_data = new FormData(); | |
| xhr = new XMLHttpRequest(); | |
| xhr.open("POST","http://barfoo.com/upload"); | |
| xhr.setRequestHeader("Content-Type","multipart/form-data"); | |
| xhr.setRequestHeader("File-Name",file.name); | |
| xhr.setRequestHeader("File-Size",(file.size || file.fileSize)); | |
| xhr.setRequestHeader("File-Type",file.type); | |
| xhr.setRequestHeader("Session-ID",12345); | |
| xhr.onreadystatechange = function __xhr_onreadystatechange__(){ | |
| if (xhr.readyState == 4) { | |
| xhr.onreadystatechange = null; | |
| if (xhr.status != 200 || xhr.responseText != "OK") { | |
| alert("Sorry, upload failed for: " + (file.name || "[unknown file]")); | |
| } | |
| xhr = null; | |
| } | |
| }; | |
| form_data.append(file.name,file); | |
| xhr.send(form_data); |
| events.js:66 | |
| throw arguments[1]; // Unhandled 'error' event | |
| ^ | |
| Error: bad content-type header, no multipart boundary | |
| at IncomingForm._parseContentType (/path/to/node_modules/formidable/lib/incoming_form.js:233:19) | |
| at IncomingForm.writeHeaders (/path/to/node_modules/formidable/lib/incoming_form.js:131:8) | |
| at IncomingForm.parse (/path/to/node_modules/formidable/lib/incoming_form.js:84:8) |
| Content-Type:multipart/form-data | |
| File-Name:blah.jpg | |
| File-Size:29080 | |
| File-Type:image/jpeg | |
| Origin:http://foobar.com | |
| Referer:http://foobar.com/blah/ | |
| Session-ID:12345 | |
| User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1215.0 Safari/537.2 | |
| Request Payload | |
| ------WebKitFormBoundary3KzOjhaAGvJbm65r | |
| Content-Disposition: form-data; name="blah.jpg"; filename="blah.jpg" | |
| Content-Type: image/jpeg | |
| ------WebKitFormBoundary3KzOjhaAGvJbm65r-- |
| // handle the HTTP routing | |
| function handleHTTP(req, res) { | |
| // handle file uploads | |
| if (req.url == "/upload") { | |
| // handle the CORS preflight request for the upload | |
| if (req.method.toLowerCase() == "options" && req.headers["access-control-request-method"].toLowerCase() == "post") { | |
| res.writeHead(200,CORS_POST_HEADERS); | |
| res.end(); | |
| return; | |
| } | |
| // are we doing a POST upload? | |
| else if (req.method.toLowerCase() == "post") { | |
| // add the CORS POST headers | |
| for (header in CORS_POST_HEADERS) { | |
| res.setHeader(header,CORS_POST_HEADERS[header]); | |
| } | |
| // parse a file upload | |
| var form = new formidable.IncomingForm(); | |
| form.parse(req,function __form_parse_cb__(err,fields,files) { | |
| if (err) { | |
| res.writeHead(500, {"Content-Type": "text/plain"}); | |
| res.end(); | |
| console.log("upload err: " + JSON.stringify(err)); | |
| } | |
| else { | |
| console.log(JSON.stringify(files)); | |
| res.writeHead(200, {"Content-Type": "text/plain"}); | |
| res.write("OK"); | |
| res.end(); | |
| } | |
| }); | |
| return; | |
| } | |
| // otherwise, bail because we won't handle this kind of request! | |
| else { | |
| // add the CORS POST headers | |
| for (header in CORS_POST_HEADERS) { | |
| res.setHeader(header,CORS_POST_HEADERS[header]); | |
| } | |
| res.writeHead(403,{"Content-Type": "text/plain"}); | |
| res.end(); | |
| return; | |
| } | |
| } | |
| return false; | |
| } | |
| require("http").createServer(handleHTTP).listen(80); |
Here's the error: https://github.com/felixge/node-formidable/blob/master/lib/incoming_form.js#L242
Seems like your content type should have boundary in it somewhere.
Ah, that makes sense. I guess the browser generates a random boundary value and appends it to the content-type. @getify have you tried leaving the content-type off to see if the xhr does the right thing? If not, you'll have to find a way to get the generated boundary and append it to the content-type. Or you'll have to generate your own boundary value and have the body use that value. I'd be interested to know how you got this working.
I took out the setting of the the content-type on the XHR object, and sure enough the browser automatically sets the content-type, including the boundary, and all works fine. Thanks for the hint, @polotek and @alFReD-NSH!
Side note: apparently you have to return CORS headers on every single response, not just in response to the preflight OPTIONS request. Had to fix that too.
This is probably just an issue with copying the data, but your request body file above doesn't seem to have line separators between headers and body. Otherwise this looks okay, but I'm not terribly familiar with submitting forms via xhr.