您的位置:首页 > 其它

浏览器上传大文件的尴尬

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. 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()) {
..............
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: