Chinaunix首页 | 论坛 | 博客
  • 博客访问: 100058
  • 博文数量: 41
  • 博客积分: 2016
  • 博客等级: 大尉
  • 技术积分: 560
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-30 17:40
文章分类
文章存档

2011年(7)

2010年(5)

2009年(19)

2008年(10)

我的朋友
最近访客

分类: Java

2009-09-26 18:14: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码的,要上传二进制文件,是否要手工将二进制用?另外,模拟表单提交上传文件都是模拟一个multipart/form-data消息,根据,使用边界(boundary)字符串将各个字段分割开,上传文件时既有描述边界格式的文本内容,也有二进制文件内容,怎样使用XMLHttpRequest.send()函数发送这种混合的内容?

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

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

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

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

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

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

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

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

阅读(1725) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~