浏览器上传大文件的尴尬
2010-05-22 15:08
92 查看
想上传超过1G的文件?
先来解读浏览器上传大文件的实际表现
1. IE 上传 1G 文件时,得到的Conent-Length 是不准确,上传3G,Content-Length 变为负数了。 囧
2. FireFox 添加后,点击提交没有反应。
再来看看标准协议 rfc1867.txt
里面有几点是关键内容
1. 上传的表单编码 必须是 multipart/form-data
2. 上传多个文件时格式有2种,一种是
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
另一种是
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data; name="pics"
Content-type: multipart/mixed, boundary=BbC04y
--BbC04y
Content-disposition: attachment; filename="file1.txt"
IE 采用的是第一种,
Java 实现注意的地方
先来解读浏览器上传大文件的实际表现
1. IE 上传 1G 文件时,得到的Conent-Length 是不准确,上传3G,Content-Length 变为负数了。 囧
2. FireFox 添加后,点击提交没有反应。
再来看看标准协议 rfc1867.txt
里面有几点是关键内容
1. 上传的表单编码 必须是 multipart/form-data
2. 上传多个文件时格式有2种,一种是
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
另一种是
Content-type: multipart/form-data, boundary=AaB03x
--AaB03x
content-disposition: form-data; name="field1"
Joe Blow
--AaB03x
content-disposition: form-data; name="pics"
Content-type: multipart/mixed, boundary=BbC04y
--BbC04y
Content-disposition: attachment; filename="file1.txt"
IE 采用的是第一种,
Java 实现注意的地方
1. Common-FileUpload 是个专门用来处理上传的公共包,里面有个 MultipartStream 可以直接用来解析协议内容。 2. 注意的是,需要要解析大文件流,不能设置Conent-Length,将此值设置为 -1 即可。如 3. 得到上传的文件名如果乱码,是因为设置的编码不对,需要设置为GBK编码。 最后,贴一下 用 JBoss Netty 实现的上传
import java.io.IOException; import java.io.InputStream; import java.util.List; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileUpload; import org.apache.commons.fileupload.FileUploadException; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; /** * 用Netty来实现上传 */ public class NettyUploader extends FileUpload { public static final boolean isMultipartContent(HttpRequest request) { if (HttpMethod.POST != request.getMethod()) { return false; } if (request.getHeaders("Content-Type") == null && request.getHeaders("Content-Type").size() == 0) { return false; } String contentType = request.getHeaders("Content-Type").get(0); if (contentType == null) { return false; } if (contentType.toLowerCase().startsWith("multipart/")) { return true; } return false; } /** * 上传的内容流 */ private InputStream inputStream; public NettyUploader(InputStream inputStream) { this.inputStream = inputStream; } public NettyUploader(FileItemFactory fileItemFactory) { super(fileItemFactory); } @SuppressWarnings("unchecked") public List<FileItem> parseRequest(String encoding, String contentType, int contentLength) throws FileUploadException { return parseRequest(new NettyRequestContext(encoding, contentType, contentLength, inputStream)); } public FileItemIterator getItemIterator(String encoding, String contentType, int contentLength) throws FileUploadException, IOException { this.setHeaderEncoding(encoding == null ? "GBK" : encoding); return super.getItemIterator(new NettyRequestContext(encoding, contentType, contentLength, inputStream)); } }
import java.io.IOException; import java.io.InputStream; import org.apache.commons.fileupload.RequestContext; /** * 实现FileUploader */ public class NettyRequestContext implements RequestContext { private String encoding; private String contentType; private long contentLength = -1; /** * 上传的内容流 */ private InputStream inputStream; public NettyRequestContext(String encoding, String contentType, long contentLength, InputStream inputStream) { this.encoding = encoding; this.contentType = contentType; this.contentLength = contentLength; this.inputStream = inputStream; } public String getCharacterEncoding() { return encoding; // return request.getHeader("Character-Encoding"); } public String getContentType() { return contentType; // return request.getHeader("Content-Type"); } public int getContentLength() { return (int) contentLength; // return (int) request.getContentLength(); } public InputStream getInputStream() throws IOException { // return new ChannelBufferInputStream(request.getContent()); // 不能直接用request的流,因为有HttpChunk return inputStream; } public String toString() { return "ContentLength=" + this.getContentLength() + ", ContentType=" + this.getContentType(); } }
NettyUploader uploader = new NettyUploader(uploadStream); // 不能读取头,因为大文件,IE的都不是正确的 FileItemIterator iterator = uploader.getItemIterator(encoding, contentType, -1); int counts = 0; while (iterator.hasNext()) { .............. }
相关文章推荐
- 【代码】Node.js模拟浏览器文件上传
- Webdriver 文件上传 & 浏览器滚动条操作 & 网页截图操作
- 【H5】手机浏览器分批次多张上传图片(文件),包含进度条
- flash + html5 实现浏览器兼容的文件上传方案
- 使用 js 获得上传文件的真实路径 chrome 浏览器 除外
- 在Android浏览器中通过WebView调用相机拍照/选择文件 上传到服务器
- Firefox浏览器中,Flex的FileReference上传文件,引发IOError
- uploadify上传文件Firefox浏览器上传失败解决方法
- ajaxFileUpload.js上传图片插件,全浏览器兼容,规避json错误,带文件格式大小拦截
- 针对不同浏览器预览上传文件的处理方式
- 浏览器上传文件到PHP的几种方法
- CSS自定义文件上传按钮样式,兼容主流浏览器
- File文件上传,不同浏览器统一表示
- input file上传文件样式支持html5的浏览器解决方案
- uploadify上传文件Firefox浏览器上传失败解决方法
- JS文件/图片从电脑里面拖拽到浏览器上传文件/图片
- 同一页面多次使用kindEditor的上传文件——兼容大部分浏览器
- Easy.Ajax 部分源代码 支持文件上传功能, 兼容所有主流浏览器
- 项目开发的时候上传更新的文件覆盖源文件刷新浏览器没有变化解决办法
- 点滴积累【C#】---对上传文件的路径进行加密,以免将路径暴露在浏览器上,避免一些安全隐患!