用xmlhttp将html的数据打包成multipart/form-data格式,实现异步上传文件功能[转]
阅读本文之前,可以先阅读RFC1867 Form Based File Upload in HTML协议。
1.
不知道为什么,在局域网,有些电脑上含有<input type="file>的<form method="post" enctype="multipart/form-data">表单提交时很快,但有些很慢。
服务器端使用过多种文件接收工具库测试如apache common file upload、jspsmartupload等等亦如此。
也换过浏览器如IE和FireFox,问题依然。
在搜索的过程中,有人说这是浏览器的限制,或者是网络问题,或者是服务器网络设定等等,但是... 没有人指出具体的解决方案,><!。
不过在多次试验下,终于发现,如果是用applet来发送或者是用xmlhttp把表单打包成multipart/form-data格式可以解决这个问题,热泪盈眶中...
当然事情不是这么顺利。首先我使用applet,但是发现该死的jre安全设定不允许访问本地文件,耗了我很多精力。虽然后来applet成功了,不过设定这么困难,而且还要下载jre,客户肯定不干。
然后我考虑在浏览器中打包数据,用流发送。首先在一个法国网站找到mozilla/firefox的解决方案,坚定了我的信心。尝试在IE里用Scripting.FileSystemObject和ADODB.Stream发送,但是ADODB.Stream蹩脚的使用方法把我困住,后来,居然在VB论坛找到了正确的api使用方法,然后我把他转成javascript,大功告成。
接着我想去测试一下firefox下的数据打包发送,安全设置的难度不亚于jre,我投降~~。
2.
现在贴一下相关帖子
最早是在javascript论坛发现此帖,几年前的事了。后来发现他是把二进制编码成String,在服务器端再反编码,太浪费了,而且java方面似乎没什么现成的反编码类库。
http://community.csdn.net/Expert/topicview.asp?id=1546672
上文提到的法国网站的帖子,他用的是mozilla的,对IE无用。
http://xulfr.org/wiki/ApplisWeb/Request
上文提到的VB论坛的帖子。
http://community.csdn.net/Expert/topic/4407/4407031.xml?temp=.8799097
感谢这些技术共享的作者。
3.
讲解一下ADODB.Stream的使用特点。
为了使用ADODB.Stream,客户端IE需要降低浏览器权限,推荐做法是把服务器网址加入到"受信任的站点",再自定义安全级别,将"对没有标记为安全的ActiveX控件进行初始化和脚本运行"设置为"启用"。
stream = new ActiveXObject('ADODB.Stream');
stream.Type = 2; // 2代表流的类型为文本
stream.CharSet = "utf-8";
stream.Open();
stream.WriteText("test string");
// 在写完文本之后,需要写入二进制内容,
// 这里是一个要点,需要把流的类型改为1,
// 但是要改变状态,就得把流的位置设置为0
// 看看下面是怎么作的
position = stream.Position; // 先记录当前位置
stream.Position = 0; // 位置设置为0
stream.Type = 1; // 改变流状态为二进制
stream.Position = position; // 恢复到改变前的位置
stream.Write(binaryData);
// 但是在发送前,还需要把流的位置设置为0,
// 因为Microsoft.XMLHttp对象不会帮我们把ADODB.Stream的位置改为0,
// 从0开始读取数据,而是从流的最后位置开始读。
stream.Position = 0;// 位置设置为0
httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
httpRequest.open("POST", "test.jsp", true);
httpRequest.setRequestHeader('Content-Type', 'multipart/form-data, boundary=' + boundary);
httpRequest.setRequestHeader("Content-Length", stream.Size);
httpRequest.send(stream); // 发送流
4.
完整的封装代码就不发出来了,没什么意义,用上文给出的三个帖子cut©就可以了。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=572530