开发者

Server error posting MIME Multipart data directly with Javascript

I am trying to build Multipart Form Data directly in Javascript in order to send my data to a server. I know there are Ajax form plugins, but I really think they wont suit my needs as I will create binary data in the browser and send it as if it were a file submit (The server I will post to requires it that way).

My problem now is that the simplest example of building text Multipart MIME data fails on the server side with an error:

500 Internal Server Error: Invalid boundary in multipart form

I have tried to reduce the code to a bare minimum: In this main.html (this is the name it will be refered to later in the server code) , there are both an html form to submit text the html-non-Ajax way and also a Javascript function which tries to replicate that with XmlHttprequest:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Posting MIME Multipart directly in Javascript</title>

<script>
function sendMimeMultipart(url, data) {

    boundary = '---------------------------1504702169761927311267328916'
    xhr = new XMLHttpRequest();

    xhr.open("POST", url);

    //Build the MIME POST request.
    var body = "--" + boundary + "\r\n";
    body += 'Content-Disposition: form-data; name="contents"\r\n\r\n';
    body += data+"\r\n";
    body += "--" + boundary + "--"+"\r\n";

    var fileSize = body.length
    xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary);
    xhr.setRequestHeader("Content-Length", fileSize);
    xhr.send(body);
    return true;
}

function sendData() {
    sendMimeMultipart('http://localhost:8080/myhandler', "Hello World!");   
}
</script>
</head>

<body onload='sendData()'> 

<form action = "myhandler" method = "post" enctype = "multipart/form-data">
    <input type = "text" name = "contents">
    <input type = "submit">
</form>

</body>
</html>

This is the Request object that arrives to the server when using the form:

Request: POST /myhandler
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3
Connection: keep-alive
Content-Length: 187
Content-Type: multipart/form-data;
boundary=---------------------------18171295601131570933197493099
Host: localhost:8080
Keep-Alive: 115
Referer: http://localhost:8080/
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; es-ES; rv:1.9.2.20) 
Gecko/20110803  Firefox/3.6.20

-----------------------------18171295601131570933197493099
Content-Disposition: form-data; name="contents"

Hello World!
-----------------------------18171295601131570933197493099--

And this the Request object arriving to the server when using the Javascript function (sendMimeMultipart):

Request: POST /myhandler
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Language: es-es,es;q=0.8,en-us;q=0.5,en;q=0.3
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 185
Content-Type: multipart/form-data; charset=UTF-8, 
boundary=---------------------------1504702169761927311267328916
Host: localhost:8080
Keep-Alive: 115
Pragma: no-cache
Referer: http://localhost:8080/
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; es-ES; rv:1.9.2.20) 
Gecko/20110803 Firefox/3.6.20

-----------------------------1504702169761927311267328916
Content-Disposition: form-data; name="contents"

Hello World!
-----------------------------1504702169761927311267328916--

The difference of 2 bytes in Content-Length is because the browser generates the boundaries randomly, being sometimes longer and sometimes shorter. In this case it is one character longer, what accounts for the two byte difference in the two boundary occurrences.

I dont think the server has much to do with this, bus just in case I开发者_Go百科 post the server side code. It is an Appengine snippet intended only for localhost usage; the call to "localhost:8080/myhandler" retrieves the value of "contents" posted by the browser and stores it in a global variable. After that, a call to "localhost:8080/show" displays the text previously retrieved. As I mentioned before, if we send the data using the form, the text content is correctly saved and the "show" handler displays it. If however we use the Javascript, the line of code:

        contents = self.request.get("contents")

In MyHandler (code below), produces the error.

Here is the server code:

import cgi
import datetime
import logging
import os

from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import images
from google.appengine.ext.webapp import template
from os import environ

contents=''

class mein(webapp.RequestHandler):
    def get(self):
        template_values = {}
        path = os.path.join(os.path.dirname(__file__), 'templates/main.html')
        self.response.out.write(template.render(path, template_values))

class MyHandler(webapp.RequestHandler):
    def post(self):
        global contents
        contents = self.request.get("contents")

class Show(webapp.RequestHandler):
    def get(self):
        global contents
        self.response.headers['Content-Type'] = "text/plain"
        self.response.out.write(contents)

application = webapp.WSGIApplication([
  ('/', mein),
  ('/myhandler', MyHandler),
  ('/show', Show)
], debug=True)

def main():
  run_wsgi_app(application)

if __name__ == '__main__':
  main()

Any idea of why this should be failing? I have tried a zillion different things, but I dont seem to be able to make it work or to understand the reason why it doesnt!.

Thanks very much in advance for your ideas and help.

All the best:

-Javier


I encountered the same error message when trying to construct a http file upload manually. I got it to work by replacing the comma(,) with a semicolon(;) in the Content-Type headers. In your case, by replacing:

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

with:

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

This seems to be related to the Python backend, because I had this same problem with Django(Python) and when I debugged it against a PHP test server both comma and semicolon worked.

Finally, the example in RFC1867 DO use a comma so in the end I'm unsure what really is the correct way to do it, but semicolon solved it for me.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜