用户登录  |  傲看软件园 用户注册
文章中心广告代码ASP源码PHP源码JSP源码.NET源码源码相关傲看留言板繁體中文
当前位置:傲看软件园文章中心技巧应用网络通讯

使用Javascript XMLHttpRequest模拟表单(Form)提交上传文件

减小字体 增大字体 作者:Fuller  来源:本站原创  发布时间:2009-09-26 17:53:19

很长时间没有遇到一个两天两夜调不通的问题了,值得花时间好好总结一下。

客户端用Javascript XMLHttpRequest在Mozilla平台上实现,服务器环境是Tomcat + Spring,以前实现过多次文件上载功能,但是以前的实现有个特点:要么客户端手工编程,要么服务器侧手工编程,但是从来没有两边都手工编程的。例如, 在客户端,直接用浏览器的Form提交,不用管底层是怎样将文件上传的,如果手工编程的话就需要使用XMLHttpRequest对象模拟浏览器的表单提 交过程。而在服务器测直接使用Spring的 org.springframework.web.servlet.mvc.SimpleFormController类,可以不管Spring是怎样解 析MultipartHttpServletRequest类型的上传请求的,如果是手工编程就需要手工辨别 MultipartHttpServletRequest请求类型,然后调用 MultipartHttpServletRequest.getFileNames()方法将上传的文件名和文件内容分别提取出来进行处理。

此次两边同时手工做,心里没有底,出了问题不知道哪一侧不对。偏偏出了问题, 服务器总是抛出异常

org.apache.commons.fileupload.FileUploadException: Read timed out

实际上在编程之前就心里开始打鼓,因为根据规范,HTTP中传送的内容是ASCII码的,要上传二进制文件,是否要手工将二进制用7bit编码?另外,模拟表单提交上传文件都是模拟一个multipart/form-data消息,根据HTML规范,使用边界(boundary)字符串将各个字段分割开,上传文件时既有描述边界格式的文本内容,也有二进制文件内容,怎样使用XMLHttpRequest.send()函数发送这种混合的内容?

带着这些问题,先上网找几个例子,先阅读了XMLHttpRequest模拟表单上传文件,照着做了出现上述异常,继续网上冲浪,奋战一天多,找了几个好的文章:一个详细的例子中文的例子和评论。异常仍然不能排除,后来将重点放在服务器侧,搜索read timed out有关的内容,很多遇到这样问题的帖子,但是没有一个合适的,后来在一个论坛帖子中,有人认为

having trouble streaming the file contents into the multi-part form post

于是将重点再次转回客户端,好像是这个原因,因为如果不用文件streaming(同时使用了nsIStringInputStream, nsIFileInputStream, nsIBinaryInputStream,nsIMultiplexInputStream等Mozilla的XPCOM对象),而是直接将内容写入, 是可以的。尝试了无数次,人越着急脑子越不好使,暂时放弃了。因为不是必须实现的功能(在网页抓取/数据抽取/异构数据对象搜索引擎工具包MetaSeeker V4版本中 这是可选功能),放弃后思想没有负担了,今天中午突然想到可能是因为XMLHttpRequest中读了两次文件,而 nsIFileInputStream设定成指针不能回零而且读到EOF就关闭流,所以第二次读时就读超时了。使用 XMLHttpRequest.send()有可能发送两次HTTP消息,因为服务器使用了HTTP Digest鉴权,所以第一次读文件流时已经读完了,第二次没的读了。下午一试即灵,这才想起中文的例子和评论那篇文章,在真正上传文件之前先发一个内容为空的用于鉴权的消息。

主要问题解决了,还有一个小问题,就是上述引用的这些例子都不能在我的环境中用,发上去的消息中无法正确解析出上传的文件来。实际上他们的程序都不符合HTML规范,详细说明如下:

在程序中定义了一个变量boundary,大部分例子中这个boundary变量的起始字符是"--",因为在HTTP消息体中要使用"--",但是,如果这样定义,那么调用

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

设置HTTP消息头的时候,就将"--"也声明进去了,我发现在我的运行环境中这样不行,如果定义的变量boundary中没有起始字符"--"就可以了。当然此时要注意在整个消息的结尾需要在boundary字符串前后都加"--",可以参照HTML规范构造符合规范的消息体。难道运行平台不一样使用方法就不一样吗?

另外还有一个疑问,程序运行结束后是否应该将打开的流都调用close()?上面的例子没有一个调用的。

Tags:网络通讯

作者:Fuller

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论

精品栏目导航

关于本站 | 网站帮助 | 广告合作 | 下载声明 | 友情连接 | 网站地图
冀ICP备08004437号 | 客服Q:354766721 | 交流群83228313
傲看软件园 - 绿色软件,破解软件下载站! 源码网 源码之家 绿软之家
Copyright © 2003-2010 OkHan.Net. All Rights Reserved .
页面执行时间:32,171.88000 毫秒
Powered by:OkHan CMS Version 4.0.0 SP2