【问题标题】:Server error posting MIME Multipart data directly with Javascript服务器错误直接使用 Javascript 发布 MIME 多部分数据
【发布时间】:2011-10-30 14:45:45
【问题描述】:

我正在尝试直接在 Javascript 中构建多部分表单数据,以便将我的数据发送到服务器。我知道有 Ajax 表单插件,但我真的认为它们不适合我的需要,因为我将在浏览器中创建二进制数据并将其发送,就好像它是文件提交一样(我将发布到的服务器需要这种方式)。

我现在的问题是构建文本 Multipart MIME 数据的最简单示例在服务器端失败并出现错误:

500 Internal Server Error: Invalid boundary in multipart form

我试图将代码减少到最低限度:在这个 main.html(这是稍后将在服务器代码中引用的名称)中,有一个 html 表单来提交文本 html-non -Ajax 方式以及尝试使用 XmlHttprequest 复制它的 Javascript 函数:

<!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>

这是使用表单时到达服务器的Request对象:

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--

这是使用Javascript函数(sendMimeMultipart)时到达服务器的Request对象:

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--

Content-Length 的 2 个字节的差异是因为浏览器随机生成边界,有时更长有时更短。在这种情况下,它长了一个字符,这是两个边界出现中两个字节差异的原因。

我认为服务器与此没有太大关系,总线以防万一我发布服务器端代码。它是一个 Appengine sn-p,仅用于本地主机;对“localhost:8080/myhandler”的调用检索浏览器发布的“contents”的值并将其存储在全局变量中。之后,调用“localhost:8080/show”会显示之前检索到的文本。正如我之前提到的,如果我们使用表单发送数据,文本内容会正确保存,并且“显示”处理程序会显示它。但是,如果我们使用 Javascript,代码行:

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

在 MyHandler(下面的代码)中,产生错误。

这是服务器代码:

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()

知道为什么这会失败吗?我尝试了无数种不同的东西,但我似乎无法让它发挥作用或理解它不起作用的原因!。

非常感谢您的想法和帮助。
万事如意:

-哈维尔

【问题讨论】:

  • 您是否尝试过从Content-Type 中删除charset 参数?在这种情况下没有意义。
  • 我不知道如何摆脱它。它是包含它的Javascript。 :-( 如果您看到接受的字符集字段,看起来 utf-8 应该不是问题。此测试仅针对文本内容,而不是二进制内容。
  • 多部分消息本身并不是真正的文本,但是,就在那里使用的意义而言——并且各个部分都有自己的内容类型。不过,这似乎不太可能是问题所在。
  • 请注意,Accept-Charset 标头指定客户端将在响应中接受的内容 - 它与服务器将接受的内容无关。
  • 这种情况发生在 dev、prod 或两者中?您如何确定正在发送的请求的内容?

标签: javascript html google-app-engine multipartform-data


【解决方案1】:

我在尝试手动构建 http 文件上传时遇到了同样的错误消息。我通过在 Content-Type 标头中用分号 (;) 替换逗号 (,) 来使其工作。在您的情况下,通过替换:

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

与:

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

这似乎与 Python 后端有关,因为我在使用 Django(Python) 时遇到了同样的问题,当我针对 PHP 测试服务器调试它时,逗号和分号都有效。

最后,RFC1867 中的示例使用逗号,所以最后我不确定真正的正确方法是什么,但分号为我解决了这个问题。

【讨论】:

    猜你喜欢
    • 2021-07-26
    • 2014-07-02
    • 1970-01-01
    • 2015-03-03
    • 1970-01-01
    • 2016-06-30
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多