项目需要做一个客户端将崩溃日志文件发送到服务器的功能,然后同事就用到了apache的commons-fileupload-1.3.1.jar这个包,部分代码如下:
ServletFileUpload upload = new ServletFileUpload();
upload.setHeaderEncoding("utf-8");
// Set overall request size constraint
upload.setSizeMax(4194304); // 设置最大文件尺寸,这里是4MB
upload.setFileSizeMax(3 * 1024 * 1024l);
FileItemIterator i = upload.getItemIterator(request);//得到所有的文件
//Iterator<FileItem> i = items.iterator();
FileOutputStream fout = null;
BufferedOutputStream bout = null;
BufferedInputStream bin = null;
try {
while (i.hasNext()) {
FileItemStream item = i.next();
String name = item.getName();
out.println(name);
InputStream stream = item.openStream();
File f = new File("/" + item.getName());
System.out.println(f.getAbsolutePath());
fout = new FileOutputStream(f);
bout = new BufferedOutputStream(fout);
bin = new BufferedInputStream(stream);
int byte_;
while ((byte_ = bin.read()) != -1) {
bout.write(byte_);
}
bout.close();
bin.close();
}
} catch (Exception e) {
e.printStackTrace();
if (fout != null) {
fout.close();
}
if (bout != null) {
bout.close();
}
if (bin != null) {
bin.close();
}
}
代码因为照着apache的格式写的,所以也没啥问题。但是每次测试都会报错,错误日志如下:
org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:1005)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.close(MultipartStream.java:943)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.close(MultipartStream.java:922)
at java.io.FilterInputStream.close(FilterInputStream.java:181)
at org.apache.commons.fileupload.util.LimitedInputStream.close(LimitedInputStream.java:164)
at java.io.BufferedInputStream.close(BufferedInputStream.java:472)
at org.apache.jsp.fileupload_jsp._jspService(fileupload_jsp.java:210)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.sharp.filter.AuthorityFilter.doFilter(AuthorityFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2441)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2430)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
网上查了一下,答案很多。大致分为以下几类:
1、session超时断开连接,解决方案:
修改tomcat配置文件server.xml,找到类似于下面配置:
<Connector port="8086" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />
将上面的参数disableUploadTimeout值改为false即可。
2、文件过大,还是修改server.xml。在connector里面添加配置 maxPostSize="0" ,0表示无限大。
<Connector port="8086" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" maxPostSize="0" />
这两种方法都尝试了,还是没找到问题所在,然后找到我,我也是最开始在stackovverflow,csdn等网站上看了各种答案并尝试还是不行。后来断点看了一下流的信息,发觉后面很大一部分数据都是空的,那么就怀疑是不是被整个框架中间拦截导致的,于是查看了一下web.xml,发现中间有个filter,而filter因为之前项目功能需求对所有请求进行了拦截和修改,于是将这个filter的代码注释之后终于成功了。
总结下来就是 查看在fileupload进行解析request之前,看看request是不是已经进行了修改。