好吧,我不得不说,到目前为止,这个问题让我难住了。我们在 Tomcat 6.0.18 中运行的 Web 应用程序在文件上传期间失败,但是仅当客户端机器是Windows机器时,仅适用于某些机器,并且适用于所有浏览器,而不仅仅是IE.
日志中有堆栈跟踪,这似乎表明客户端关闭了连接,或者流以某种方式损坏。堆栈跟踪中的根本原因如下:
Caused by: org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:983)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:887)
at java.io.InputStream.read(InputStream.java:85)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:94)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:64)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:362)
... 70 more
导致跟踪的代码看起来相当简单。
private Map<String, Object> getMap( ActionRequest request ) {
HashMap<String, Object> parameters = new HashMap<String, Object>();
if ( request == null ) {
return parameters;
}
if ( request.getContentType() == null ) {
return parameters;
}
try {
if(PortletFileUpload.isMultipartContent(request)){
DiskFileItemFactory factory = new DiskFileItemFactory();
PortletFileUpload upload = new PortletFileUpload(factory);
List<DiskFileItem> fileItems = upload.parseRequest(request);
for( DiskFileItem fileItem : fileItems ) {
String name = fileItem.getFieldName();
//now set appropriate variable, populate hashtable
if( fileItem.isFormField() ) {
String value = fileItem.getString( request.getCharacterEncoding() );
if( parameters.get( name ) == null ) {
String[] values = new String[1];
values[0] = value;
parameters.put( name, values );
} else {
Object prevobj = parameters.get( name );
if( prevobj instanceof String[] ) {
String[] prev = ( String[] ) prevobj;
String[] newStr = new String[prev.length + 1];
System.arraycopy(
prev, 0, newStr, 0,
prev.length
);
newStr[prev.length] = value;
parameters.put( name, newStr );
} else {
//now what? I think this breaks the standard.
throw new EatMyHatException(
"file and input field with same name?"
);
}
}
} else {
// Yes, we don't return FileParameter[] for multiple files of same name. AFAIK, that's not allowed.
FileParameter fp = new FileParameter( fileItem );
parameters.put( name, fp );
files.add( fp );
}
}
} else {
// Not multipart
return toObjectMap(request.getParameterMap());
}
} catch (FileUploadException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return parameters;
}
给我们带来悲伤的是这一行:
List<DiskFileItem> fileItems = upload.parseRequest(request);
由于某种原因,确定来自某些 Windows 计算机的流在某种程度上已损坏。
我想我找到了一些东西可能相关在 StackOverflow 上。这似乎表明 Tomcat 6 中存在一些错误,该错误已在版本 6.0.20 中修复,该版本比我们正在使用的版本稍高。不幸的是,它没有提到问题本身是什么。我有看过了在 Tomcat 变更日志中,但看不到任何可能导致此问题的错误。
无论如何,关于我的实际问题,有没有人遇到过类似的问题,如果是的话,根本问题是什么以及您是如何解决的?
预先感谢您的任何回复。
编辑:这似乎是负载平衡和 Tomcat 的某种问题。如果绕过负载均衡器并直接通过服务器IP地址访问Tomcat,问题就会消失。奇怪的是,这出现在我们使用 Apache/AJP1.3 的临时环境和使用 Zeus 的实时环境中。
EDIT3:事实证明这是客户端防火墙的问题。看来他们……呃……当他们说他们肯定知道这不是防火墙问题时,他们并不完全诚实。