【问题标题】:issues with form/iframe based file upload in OperaOpera 中基于表单/iframe 的文件上传问题
【发布时间】:2023-03-24 04:45:01
【问题描述】:

解决方案

参考下面我的回答:issues with form/iframe based file upload in Opera


每当浏览器不支持 XMLHttpRequest 上传 (Opera) 时,我都会使用表单/iframe 技术将文件发送到服务器。在高层次上,这是设置...

  1. 创建一个 iframe <iframe src="javascript:false;" name="file-iframe"></iframe>
  2. 创建一个表单<form enctype="multipart/form-data" method="POST">
    • 设置目标 = iframe 的名称,target="file-iframe"
    • 设置操作 = 网址,action="/upload"
  3. 将文件输入添加到表单中
  4. 提交表格

表单提交时,服务器吐出异常:

org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
    at org.apache.commons.fileupload.MultipartStream.readHeaders(MultipartStream.java:538)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:999)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:965)
    at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
    at org.apache.commons.fileupload.servlet.ServletFileUpload.getItemIterator(ServletFileUpload.java:148)
    at com.beamit.jetty.UploadServlet.doPost(UploadServlet.java:28)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    ...
    ...

这是UploadServlet.java文件中的代码sn-p,失败发生在sn-p的最后一行:

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {

    ServletFileUpload up = new ServletFileUpload();
    try {
        FileItemIterator iter = up.getItemIterator(request); // <------ ERROR
        ...
    } catch (IOException e) {
        e.printStackTrace();
    }
    ...

我已经尝试调试了好几个小时,但我一无所获。关于为什么会发生这种情况的任何想法?

我可以使用不同的浏览器为工作/非工作文件上传提供 HTTP 请求,如果需要,还可以提供更多源代码。

更多信息

Chrome 中对简单“hello world”文本文件的 HTTP 请求。

POST /upload/0145c HTTP/1.1
Host: beamit:8080
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Referer: http://beamit:8080/
Content-Length: 44
Origin: http://beamit:8080
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryQes3eWoFE2iw6kGE

Opera 中对简单“hello world”文本文件的 HTTP 请求。

POST /upload/f889b HTTP/1.1
User-Agent: Opera/9.80 (Macintosh; Intel Mac OS X 10.7.2; U; en) Presto/2.9.168 Version/11.52
Host: beamit:8080
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en,en-US;q=0.9,ja;q=0.8,fr;q=0.7,de;q=0.6,es;q=0.5,it;q=0.4,pt;q=0.3,pt-PT;q=0.2,nl;q=0.1,sv;q=0.1,nb;q=0.1,da;q=0.1,fi;q=0.1,ru;q=0.1,pl;q=0.1,zh-CN;q=0.1,zh-TW;q=0.1,ko;q=0.1,ar;q=0.1,cs;q=0.1,hu;q=0.1,tr;q=0.1
Accept-Encoding: gzip, deflate
Referer: http://beamit:8080/
Cookie: __utma=248039316.1622718495.1317335167.1319648741.1319655028.19; __utmb=248039316.4.10.1319655028; __utmc=248039316; __utmz=248039316.1317335167.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Connection: Keep-Alive
Content-Length: 76
Content-Type: multipart/form-data; boundary=----------cah2BDOhbumylzxVY398ZJ

【问题讨论】:

    标签: java file-upload apache-commons


    【解决方案1】:

    特定异常表明客户端已中止请求。我不确定确切的原因,但众所周知,Opera 将 iframe 和 JavaScript 结合起来很麻烦。

    我强烈建议获取一个模拟 ajax 文件上传作业的现有库,而不是自己重新发明轮子。我在您的问题历史中看到您熟悉 jQuery。例如,您可以使用jQuery form plugin 来实现最佳的跨浏览器兼容魔法,如下所示:

    <script src="jquery.js"></script>
    <script src="jquery.form.js"></script>
    <script>
        $(document).ready(function() {
            $('#formid').ajaxForm();
        });
    </script>
    ...
    <form id="formid">
        <input type="file" name="file" />
        <input type="submit" />
    </form>
    

    如有必要,您可以查看jquery.form.js 来源here,了解他们如何解决浏览器特定问题。

    【讨论】:

    • 我不是在做文件上传...我在做一个文件“流”。所以我不能完全使用现有的库,但我可以查看源代码以找出一些东西。也就是说,我仍然需要弄清楚请求被破坏的原因。
    • 我看不出“文件上传”和“文件流”有什么不同。毕竟只是一个multipart/form-data POST 请求。至于具体问题,只能怪 Opera。
    • 哈哈哈... 只怪 Opera :D 我同意,但这并不能解决问题 ;) 问题的一部分似乎是提交表单时没有发送表单数据...Content-Length: 76 告诉我,我正在发送的 2MB 文件没有被发送
    • 我会开始检查不同浏览器生成的 HTTP 流量,例如 Fiddler2,并比较特别是请求标头和正文的差异。如果 Opera 存在差异,那么它(或您负责创建 iframe 的 DOM 的 JS 代码)很可能是罪魁祸首。或者如果没有差异,那么服务器端可能会受到指责(恕我直言,这不太可能,Commons FileUpload 非常强大)。
    • 您可以这样做,但请使用带有“Hello World”行或其他内容的简单文本文件,而不是 2MB 和可能的二进制文件。
    【解决方案2】:

    我发现了问题所在。在剥离所有不必要的代码和标记后,我得到了一个简单的表单/iframe 文件上传页面。

    当我动态构建表单时,我将文件输入元素作为子元素插入:

    <input type="file" id="file-select-input" />
    

    ...我有这样的事情:

    <form enctype="multipart/form-data" id="file-select-form" target="select-file-iframe" method="POST" action="/upload/">
        <div id="file-select-button" class="">
            <input type="file" id="file-select-input" />
        </div>
    </form>
    <iframe style="display: none" id="select-file-iframe" src="javascript:false;" name="select-file-iframe"></iframe>
    

    这个设置给我带来了问题。经过一番调查,事实证明,当我提交上述表单时,没有发送输入文件信息。事实证明,这样做的原因是我没有在文件输入元素上指定name 属性。所以当我把它改成这样时:

    <input type="file" id="file-select-input" name="file" />
    

    ...一切正常。

    【讨论】:

    • 我发现如果 URL 名称中包含“localhost”,那么使用 iframe 上传文件将无法在 Opera 中使用。用机器名替换 localhost 后,它工作正常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 2021-09-26
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多