todo: 这个需要按数据流向,对数据进行梳理,标明关键配置
tomcat nginx默认的post大小限制
执行大文件上传,或者,大数据量提交时,当提交的数据大小超过一定限制时,发现后台从request取值的代码request.getParameter("message")返回值为null,原因是因为服务器对于提交的post请求的大小有一定的限制
tomcat:默认大小2097152,当maxPostSize=0时,不限制;maxPostSize=20971520时,为20M
nginx:默认的最大请求body大小为8m,修改设置client_max_body_size=100m;
resin:没有发现默认限制请求大小的地方!
Tomcat:
server.tomcat.max-connections=0 # Maximum number of connections that the server accepts and processes at any given time.
server.tomcat.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header.
server.tomcat.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content.
server.tomcat.max-threads=0 # Maximum number of worker threads.
server.tomcat.min-spare-threads=0 # Minimum number of worker threads.
undertow:
server.undertow.buffer-size= # Size of each buffer, in bytes.
server.undertow.direct-buffers= # Whether to allocate buffers outside the Java heap.
server.undertow.io-threads= # Number of I/O threads to create for the worker.
server.undertow.eager-filter-init=true # Whether servlet filters should be initialized on startup.
server.undertow.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content.
server.undertow.worker-threads= # Number of worker threads.
https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/
Spring MVC上传文件原理和resolveLazily说明
问题:使用Spring MVC上传大文件,发现从页面提交,到进入后台controller,时间很长。怀疑是文件上传完成后,才进入。由于在HTTP首部自定义了“Token”字段用于权限校验,Token的有效时间很短,因此上传大文件时,就会验证Token失败。
示例代码:
前端:
<form action="upload" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>文件描述:</td>
<td><input type="text" name="description"></td>
</tr>
<tr>
<td>请选择文件:</td>
<td><input type="file" name="file"></td>
</tr>
<tr>
<td><input type="submit" value="上传"></td>
</tr>
</table>
</form>
controller:
@RequestMapping(value="/upload",method=RequestMethod.POST)
public String upload(HttpServletRequest request,
@RequestParam("description") String description,
@RequestParam("file") MultipartFile file) throws Exception {
System.out.println("enter controller.");
}
springmvc-config.xml配置:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>524288000</value>
</property>
<property name="defaultEncoding">
<value>UTF-8</value>
</property>
</bean>
Spring MVC上传文件使用了Commons FileUpload类库,即 CommonsMultipartResolver 使用 commons Fileupload 来处理 multipart 请求,将Commons FileUpload的对象转换成了Spring MVC的对象。
那如果直接使用Commons FileUpload来进行文件上传下载呢?
示例代码:
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("enter servlet");
}
发现从页面提交,很快就进入了servlet。
既然Spring也是使用了Commons FileUpload类库,但为什么差别这么大呢?Spring在转换过程中做了什么其他操作呢?
发现 有个resolveLazily 是判断是否要延迟解析文件(通过XML可以设置)。当 resolveLazily 为 flase 时,会立即调用 parseRequest() 方法对请求数据进行解析,然后将解析结果封装到 DefaultMultipartHttpServletRequest 中;而当 resolveLazily 为 true 时,会在 DefaultMultipartHttpServletRequest 的 initializeMultipart() 方法调用 parseRequest() 方法对请求数据进行解析,而 initializeMultipart() 方法又是被 getMultipartFiles() 方法调用,即当需要获取文件信息时才会去解析请求数据,这种方式用了懒加载的思想。
再次修改代码:
1、在springmvc-config.xml增加一个配置resolveLazily,设置true;
2、将controller方法中将@RequestParam("file") MultipartFile file注释
再次测试,发现还是不对。。增加打印日志后发现:
@RequestMapping(value="/upload",method=RequestMethod.POST)
public String upload(HttpServletRequest request,
@RequestParam("description") String description,
/*@RequestParam("file") MultipartFile file*/) throws Exception {
System.out.println("enter controller.");
System.out.println(request.getHeader("Accept"));
System.out.println(request.getParam("description"));
}
第1,2条日志很快打印,第3条日志仍是文件上传完后才打印。简单分析下,应该是后台一直在接收数据,HTTP首部很快就能获取到并解析出来(首部和正文之间有一个空行),但请求正文部分必须在请求数据完全接收后才能解析,因此线程一直阻塞直到数据接收完成才打印第3条日志。因此解决方案是,把controller函数中的@RequestParam("description") String description也注释掉,这样页面提交后,会立即进入controller中。
总结下最终的解决方案:
1、springmvc-config.xml增加一项配置:
<property name="resolveLazily ">
<value>true</value>
</property>
2、在controller的方法参数中,不能附加请求参数,应在函数中自己解析参数。
#org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (1491511) exceeds the configured maximum (1048576)
spring.http.multipart.max-request-size=1MB
如果上传文件大于1MB,会报错:
配置:
#upload
#org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (1491511) exceeds the configured maximum (1048576)
spring.http.multipart.max-request-size=1MB
#org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.
spring.http.multipart.max-file-size=100MB
# Maximum size, in bytes, of the HTTP post content。this configuration maybe not needed
server.tomcat.max-http-post-size=1
报错信息:
2018-05-08 13:46:43.090 ERROR 13780 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (1491511) exceeds the configured maximum (1048576)] with root cause
org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (1491511) exceeds the configured maximum (1048576)
at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:805) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:256) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:280) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.Request.parseParts(Request.java:2869) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.Request.parseParameters(Request.java:3216) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.Request.getParameter(Request.java:1137) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:381) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:75) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.27.jar:8.5.27]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.27.jar:8.5.27]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
#org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.
spring.http.multipart.max-file-size=100MB
如果上传文件大于1MB,则会报错:
配置:
#upload
#org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (1491511) exceeds the configured maximum (1048576)
spring.http.multipart.max-request-size=100MB
#org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.
spring.http.multipart.max-file-size=1MB
# Maximum size, in bytes, of the HTTP post content。this configuration maybe not needed
server.tomcat.max-http-post-size=1
报错信息:
2018-05-08 13:51:05.533 ERROR 1616 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.] with root cause
org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.
at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl$FileItemStreamImpl$1.raiseError(FileUploadBase.java:630) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.checkLimit(LimitedInputStream.java:76) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:135) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at java.io.FilterInputStream.read(FilterInputStream.java:107) ~[na:1.8.0_144]
at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:98) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:68) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:293) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.Request.parseParts(Request.java:2869) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.Request.parseParameters(Request.java:3216) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.Request.getParameter(Request.java:1137) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:381) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:75) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.27.jar:8.5.27]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.27.jar:8.5.27]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.27.jar:8.5.27]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
从上面看,tomcat的配置好像并没有什么用:
# Maximum size, in bytes, of the HTTP post content。this configuration maybe not needed
server.tomcat.max-http-post-size=1
spring boot 版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
</parent>
Is there a maximum file size that spring boot can handle in a MultipartFile upload process.
maxFileSize and max-request-size in the property.
https://stackoverflow.com/questions/34177873/max-limit-of-multipartfile-in-spring-boot
# MULTIPART (MultipartProperties)
spring.servlet.multipart.enabled=true # Whether to enable support of multipart uploads.
spring.servlet.multipart.file-size-threshold=0 # Threshold after which files are written to disk. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively.
spring.servlet.multipart.location= # Intermediate location of uploaded files.
spring.servlet.multipart.max-file-size=1MB # Max file size. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively.
spring.servlet.multipart.max-request-size=10MB # Max request size. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively.
spring.servlet.multipart.resolve-lazily=false # Whether to resolve the multipart request lazily at the time of file or parameter access.
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
//单个文件最大
factory.setMaxFileSize("10240KB"); //KB,MB
/// 设置总上传数据总大小
factory.setMaxRequestSize("102400KB");
return factory.createMultipartConfig();
}
To upload files with Servlet containers, you need to register a MultipartConfigElement class (which would be <multipart-config> in web.xml). Thanks to Spring Boot, everything is auto-configured for you!
The multipart settings are constrained as follows:
spring.http.multipart.max-file-size is set to 128KB, meaning total file size cannot exceed 128KB.
spring.http.multipart.max-request-size is set to 128KB, meaning total request size for a multipart/form-data cannot exceed 128KB.
https://spring.io/guides/gs/uploading-files/
Servlet容器的限制 【这个配置好像不重要,为什么呢?】:
Tomcat:
server.tomcat.max-connections=0 # Maximum number of connections that the server accepts and processes at any given time.
server.tomcat.max-http-header-size=0 # Maximum size, in bytes, of the HTTP message header.
server.tomcat.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content.
server.tomcat.max-threads=0 # Maximum number of worker threads.
server.tomcat.min-spare-threads=0 # Minimum number of worker threads.
undertow:
server.undertow.buffer-size= # Size of each buffer, in bytes.
server.undertow.direct-buffers= # Whether to allocate buffers outside the Java heap.
server.undertow.io-threads= # Number of I/O threads to create for the worker.
server.undertow.eager-filter-init=true # Whether servlet filters should be initialized on startup.
server.undertow.max-http-post-size=0 # Maximum size, in bytes, of the HTTP post content.
server.undertow.worker-threads= # Number of worker threads.
https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/
大文件上传失败原因之:Tomcat HttpPost超过大小和超时
应该是Tomcat或者Nginx的配置中限制了HttpPost的大小。于是我
Nginx中限制请求大小的地方是如下的client_max_body_size,我们图方便,直接分3000m,应该足矣:
location /app {
proxy_pass http://server_name;
client_max_body_size 3000m;
access_log off;
}
Tomcat则是在server.xml中的connector元素中添加:maxPostSize=” ” ;“ ”中填你需要限制到的大小,如“0”为不限制。缺省这个参数,就会是2m.
所以应该是这里出了问题。于是我添加一行maxPostSize=”0″:
<Connector port="8038" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8028" URIEncoding="UTF-8"
maxThreads="1000"
maxPostSize="0"
minSpareThreads="25" maxSpareThreads="75"
acceptCount="200" />
上传还是失败。
因为HttpPost不仅是大小会限制,还会有时间限制。虽然你可以上传了,但你在connectionTimeout的限制时间内不能传完,连接也会断开的。
所以再将它修改如下,原先的connectionTimeout时间是“20000”,但是注意,单位是毫秒啊……于是我把它加到”2000000“,有半小时以上,足矣吧:
<Connector port="8038" protocol="HTTP/1.1"
connectionTimeout="2000000"
redirectPort="8028" URIEncoding="UTF-8"
maxThreads="1000"
maxPostSize="0"
minSpareThreads="25" maxSpareThreads="75"
acceptCount="200" />
实测成功。
spring-boot上传文件MultiPartFile获取不到文件问题解决
1.现象是在spring-boot里加入commons-fileupload jar并且配置了mutilPart的bean,在upload的POST请求后,发现multipartRequest.getFiles("file")=null,有点奇怪,查了文档资料才解决。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600"/>
<property name="maxInMemorySize" value="4096"/>
</bean>
2.原因是:spring-boot自带的org.springframework.web.multipart.MultipartFile
和Multipart产生冲突,如果同时使用了MultipartResolver 和ServletFileUpload,就会在iter.hasNext()返回false.然后整个循环就跳出去了。
整个问题产生的原因是Spring框架先调用了MultipartResolver 来处理http multi-part的请求。这里http multipart的请求已经消耗掉。
后面又交给ServletFileUpload ,那么ServletFileUpload 就获取不到相应的multi-part请求。
因此将multipartResolve配置去除,问题就解决了。
Tips:关于multipartResolver
Spring上传文件,图片,以及常见的问题
1. 在工程依赖库下添加文件上传jar包
commons-fileupload-1.2.2.jar
commons-io-2.4.jar
2.在springMVC配置文件中配置视图解析multipartResolver
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5000000" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
这里有个问题需要注意一下,Bean 的id必须为multipartResolver,因为在项目初始化的时候,Spring容器会通过这个id来进行注入,下面是Spring源码:
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;
/*
省略一大堆代码
*/
/**
* Initialize the MultipartResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* no multipart handling is provided.
*/
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
}
}
}
接下来,我们测试一下如果写错之后会报什么错误
上面只是DEBUG, 查看源码就会知道会DEBUG输出这一句,
下面是具体报的错误:预期的MultipartHttpServletRequest:是否配置了MultipartResolver?
Expected MultipartHttpServletRequest:is a MultipartResolver configured
下面依次是jsp代码和后台实现上传的java代码:
<form id="userForm" name="userForm" method="post"
action="${pageContext.request.contextPath }/user/useraddsave.html"
enctype="multipart/form-data">
<div>
<label for="a_idPicPath">证件照:</label> <input type="file"
name="a_idPicPath" id="a_idPicPath" /> <font color="red"></font>
</div>
<div class="providerAddBtn">
<input type="button" name="add" id="add" value="保存"> <input
type="button" id="back" name="back" value="返回">
</div>
</form>
//保存新增用户信息
@RequestMapping(value="/useraddsave.html",method=RequestMethod.POST)
public String addUserSave(User user,HttpServletRequest request,@RequestParam(value="a_idPicPath",required=false) MultipartFile multipartFile){
if(!multipartFile.isEmpty()){
String path = "/statics"+File.separator+"upload"; //文件或者图片上传到的位置
String oldName = multipartFile.getOriginalFilename(); //上传的文件名
String prefix = FilenameUtils.getExtension(oldName); //文件的后缀名
int maxSize =5000000;
if(multipartFile.getSize()<maxSize){
if(prefix.equalsIgnoreCase("jpg")|| prefix.equalsIgnoreCase("png")){
String fileName = System.currentTimeMillis()+RandomUtils.nextInt(1000000)+"_Personal."+prefix; // 为避免文件名一样随机生成的文件名保存在服务器
File targetFile = new File(path,fileName);
if(!targetFile.exists()){
targetFile.mkdirs();
}
try {
multipartFile.transferTo(targetFile); //开始上传
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
request.setAttribute("uploadFileError", "上傳出現異常,上傳失敗");
}
String idPicPath= path+File.separator+fileName;
user.setIdPicPath(idPicPath);
user.setCreationDate(new Date());
userService.add(user);
return "redirect:/user/userlist.html";
} else {
request.setAttribute("uploadFileError", "文件格式錯誤,上傳失敗");
}
} else {
request.setAttribute("uploadFileError", "文件太大,上傳失敗");
}
}
return "useradd";//新增失败返回到useradd.jsp
}
方法需要添加参数 @RequestParam(value="a_idPicPath",required=false) MultipartFile multipartFile
tomcat nginx默认的post大小限制
执行大文件上传,或者,大数据量提交时,当提交的数据大小超过一定限制时,发现后台从request取值的代码request.getParameter("message")返回值为null,原因是因为服务器对于提交的post请求的大小有一定的限制
tomcat:默认大小2097152,当maxPostSize=0时,不限制;maxPostSize=20971520时,为20M
nginx:默认的最大请求body大小为8m,修改设置client_max_body_size=100m;
resin:没有发现默认限制请求大小的地方!
tomcat:maxPostSize
The maximum size in bytes of the POST which will be handled by the container FORM URL parameter parsing.
The limit can be disabled by setting this attribute to a value less than or equal to 0. If not specified, this attribute is set to 2097152 (2 megabytes).
Nginx的"413 request entiry too large"
tomcat返回400
tomcat请求端口都加上maxPostSize="0"
tomcat默认参数是为开发环境制定,而非适合生产环境,尤其是内存和线程的配置,默认都很低,容易成为性能瓶颈。
| The maximum size in bytes of the POST which will be handled by the container FORM URL parameter parsing. The limit can be disabled by setting this attribute to a value less than or equal to 0. If not specified, this attribute is set to 2097152 (2 megabytes). |
| The maximum size in bytes of the POST which will be saved/bufferedby the container during FORM or CLIENT-CERT authentication. For both types of authentication, the POST will be saved/buffered before the user is authenticated. For CLIENT-CERT authentication, the POST is buffered for the duration of the SSL handshake and the buffer emptied when the request is processed. For FORM authentication the POST is saved whilst the user is re-directed to the login form and is retained until the user successfully authenticates or the session associated with the authentication request expires. The limit can be disabled by setting this attribute to -1. Setting the attribute to zero will disable the saving of POST data during authentication . If not specified, this attribute is set to 4096 (4 kilobytes). |
| The maximum queue length for incoming connection requests when all possible request processing threads are in use. Any requests received when the queue is full will be refused. The default value is 100. |
| The maximum number of unused request processing threads that will be allowed to exist until the thread pool starts stopping the unnecessary threads. The default value is 50. |
| The maximum number of request processing threads to be created by this Connector, which therefore determines the maximum number of simultaneous requests that can be handled. If not specified, this attribute is set to 200. |
| The number of request processing threads that will be created when this Connector is first started. The connector will also make sure it has the specified number of idle processing threads available. This attribute should be set to a value smaller than that set for |
http://tomcat.apache.org/tomcat-5.5-doc/config/http.html
之前我以为是method=post的问题,删除 method=post 就好了,其实是请求变成了get所以好了,今天才发现是 server.xml 里面有一个设置在作怪!
删掉这两项就好了!
上网查了一下 maxPostSize 和 maxSavePostSize 是设置最大的表单长度的,给我设成1了!结果post表单没了!
tomcat内存优化
linux修改TOMCAT_HOME/bin/catalina.sh,在前面加入
JAVA_OPTS="-XX:PermSize=64M -XX:MaxPermSize=128m -Xms512m -Xmx1024m -Duser.timezone=Asia/Shanghai"
windows修改TOMCAT_HOME/bin/catalina.bat,在前面加入
set JAVA_OPTS=-XX:PermSize=64M -XX:MaxPermSize=128m -Xms512m -Xmx1024m
最大堆内存是1024m,对于现在的硬件还是偏低,实施时,还是按照机器具体硬件配置优化。
tomcat 线程优化
<Connector port="80" protocol="HTTP/1.1" maxThreads="600" minSpareThreads="100" maxSpareThreads="500" acceptCount="700"
connectionTimeout="20000" redirectPort="8443" />
maxThreads="600" ///最大线程数 minSpareThreads="100"///初始化时创建的线程数 maxSpareThreads="500"///一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。 acceptCount="700"//指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
这里是http connector的优化,如果使用apache和tomcat做集群的负载均衡,并且使用ajp协议做apache和tomcat的协议转发,那么还需要优化ajp connector。
<Connector port="8009" protocol="AJP/1.3" maxThreads="600" minSpareThreads="100" maxSpareThreads="500" acceptCount="700"
connectionTimeout="20000" redirectPort="8443" />
由于tomcat有多个connector,所以tomcat线程的配置,又支持多个connector共享一个线程池。
首先。打开/conf/server.xml,增加
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500" minSpareThreads="20" maxIdleTime="60000" />
最大线程500(一般服务器足以),最小空闲线程数20,线程最大空闲时间60秒。
然后,修改<Connector ...>节点,增加executor属性,executor设置为线程池的名字:
<Connector executor="tomcatThreadPool" port="80" protocol="HTTP/1.1" connectionTimeout="60000" keepAliveTimeout="15000" maxKeepAliveRequests="1" redirectPort="443" />
可以多个connector公用1个线程池,所以ajp connector也同样可以设置使用tomcatThreadPool线程池。
禁用DNS查询
当web应用程序向要记录客户端的信息时,它也会记录客户端的IP地址或者通过域名服务器查找机器名 转换为IP地址。
DNS查询需要占用网络,并且包括可能从很多很远的服务器或者不起作用的服务器上去获取对应的IP的过程,这样会消耗一定的时间。
修改server.xml文件中的Connector元素,修改属性enableLookups参数值: enableLookups="false"
如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名,若为false则不进行DNS查询,而是返回其ip地址
设置session过期时间
conf\web.xml中通过参数指定:
<session-config>
<session-timeout>180</session-timeout>
</session-config>
单位为分钟。
Apr插件提高Tomcat性能
Tomcat可以使用APR来提供超强的可伸缩性和性能,更好地集成本地服务器技术.
APR(Apache Portable Runtime)是一个高可移植库,它是Apache HTTP Server 2.x的核心。APR有很多用途,包括访问高级IO功能(例如sendfile,epoll和OpenSSL),OS级别功能(随机数生成,系统状态等等),本地进程管理(共享内存,NT管道和UNIX sockets)。这些功能可以使Tomcat作为一个通常的前台WEB服务器,能更好地和其它本地web技术集成,总体上让Java更有效率作为一个高性能web服务器平台而不是简单作为后台容器。
在产品环境中,特别是直接使用Tomcat做WEB服务器的时候,应该使用Tomcat Native来提高其性能
要测APR给tomcat带来的好处最好的方法是在慢速网络上(模拟Internet),将Tomcat线程数开到300以上的水平,然后模拟一大堆并发请求。 如果不配APR,基本上300个线程狠快就会用满,以后的请求就只好等待。但是配上APR之后,并发的线程数量明显下降,从原来的300可能会马上下降到只有几十,新的请求会毫无阻塞的进来。 在局域网环境测,就算是400个并发,也是一瞬间就处理/传输完毕,但是在真实的Internet环境下,页面处理时间只占0.1%都不到,绝大部分时间都用来页面传输。如果不用APR,一个线程同一时间只能处理一个用户,势必会造成阻塞。所以生产环境下用apr是非常必要的。
(1)安装APR tomcat-native
apr-1.3.8.tar.gz 安装在/usr/local/apr
#tar zxvf apr-1.3.8.tar.gz
#cd apr-1.3.8
#./configure;make;make install
apr-util-1.3.9.tar.gz 安装在/usr/local/apr/lib
#tar zxvf apr-util-1.3.9.tar.gz
#cd apr-util-1.3.9
#./configure --with-apr=/usr/local/apr ----with-java-home=JDK;make;make install
#cd apache-tomcat-6.0.20/bin
#tar zxvf tomcat-native.tar.gz
#cd tomcat-native/jni/native
#./configure --with-apr=/usr/local/apr;make;make install
(2)设置 Tomcat 整合 APR
修改 tomcat 的启动 shell (startup.sh),在该文件中加入启动参数:
CATALINA_OPTS="$CATALINA_OPTS -Djava.library.path=/usr/local/apr/lib" 。
(3)判断安装成功:
如果看到下面的启动日志,表示成功。
2007-4-26 15:34:32 org.apache.coyote.http11.Http11AprProtocol init
参考 http://blog.sina.com.cn/s/blog_417b97470100glmi.html
http://datadig.blog.163.com/blog/static/171229928201082075946726/
标签:文件,27,8.5,tomcat,core,专题,org,java,上传 From: https://blog.51cto.com/u_15147537/5989228