最近在做一个文件上传需求,发现当上传文件大于60M时,前端ajax文件上传后,服务请求不到服务端。
排查过程:
第一步,先查前端代码如下:前端在上传文件请求后,设置10S的请求超时时间,初步猜测是上传文件较大,前端请求包还没有发送完毕就中断请求了,于是把timeout时间设置加大,增加到20秒,发现60多M的文件上传成功。
1 $.ajax({ 2 url: '/upload_url', 3 type: 'post', 4 data: data, 5 timeout: 10000, // 超时 6 cache: false, 7 processData: false, 8 contentType: false, 9 success: function(json) { 10 ....... 11 } 12 }, 13 error: function() { 14 15 }, 16 complete: function(XMLHttpRequest, status) { 17 if (status === 'timeout') { 18 // 超时直接提示 19 // '上传时间较长,请稍后查看结果', 20 }); 21 } 22 } 23 })
第二步,测试上传文件大于100M时的情况,发现服务端不会接收到请求,加大了超时时间也没有任何效果,排查Nginx配置上传文件大小限制是300M,即 client_max_body_size 300m。
并且发现Nginx如下日志:
。。。。。。。。。。。a client request body is buffered to a temporary file /dev/。。。。。。。/client_body/XXXXXXX, client
。。。。。。。。。。。pwrite() "/dev/。。。。。。。/client_body/XXXXXXX" Failed (28: No space left on device), client
所以,优化Nginx配置,client_max_body_size 300m; client_body_buffer_size 300m; 加大上传缓存Buffer size文件,reload Nginx生效。
ps :
client_max_body_size
此指令设置Nginx能处理的最大请求主体大小。 如果请求大于指定的大小,则Nginx发回HTTP 413(Request Entity too large)错误。 如果服务器处理大文件上传,则该指令非常重要。
client_body_buffer_size
此指令设置用于请求主体的缓冲区大小。 如果主体超过缓冲区大小,则完整主体或其一部分将写入临时文件。 如果Nginx配置为使用文件而不是内存缓冲区,则该指令会被忽略。 默认情况下,该指令为32位系统设置一个8k缓冲区,为64位系统设置一个16k缓冲区。 该指令在Nginx配置的http,server和location区块使用。
第三步,继续测试100M以上的文件,仍然不成功,浏览器前端请求结果返回 net::ERR_INCOMPLETE_CHUNKED_ENCODING,于是排查Nginx日志如下:
。。。。。。。。。 错误日志全部是104: Connection reset by peer) while reading upstream
显然,由于upstream重置连接了,就是说后端主动断开了连接,然后发现连接里有很多TIME-WAIT,一直等待远程TCP接收到连接中断请求的确认
。于是分析Nginx配置,Nginx作为反向代理既然是客户端又是服务端,当和后端服务建立连接时并没有默认开启长连接,开启长连接后性能应该会提升很多,于是优化Nginx配置开启Nginx长链接【说明:(从client到Nginx的连接是长连接,对于客户端来说,Nginx长连接是默认开启的。从Nginx到server的连接是长连接,需要自己开启】。
配置如下:
proxy_connect_timeout 120; proxy_send_timeout 200;
proxy_read_timeout 300;
proxy_http_version 1.1; ##开启后端,长连接
proxy_set_header Connection ""; ##开启后端,长连接 Nginx reload 生效。 第四步, 重新上传大于100M的文件,这次上面的Nginx报错问题解决,但仍然没有成功,因为上一步,已经可以确认上传文件请求已经发送到服务端,于是排查服务端日志,发现异常日志如下: org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size of 104857600 bytes exceeded; nested exception is org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (240330252) exceeds the configured maximum (104857600)
org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:162)
org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:142)
org.springframework.web.servlet.dispatcherServlet.checkMultipart(dispatcherServlet.java:1099)
org.springframework.web.servlet.dispatcherServlet.dodispatch(dispatcherServlet.java:932)
org.springframework.web.servlet.dispatcherServlet.doService(dispatcherServlet.java:897)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741) 通过上面的报错日志,定位到CommonsMultipartResolver的maxUploadSize配置设置成100M大小,于是加大此配置,如下参考。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">修改服务端文件大小校检,重新编辑发布服务端服务,问题解决。经测试300M以内文件上传没有问题。 当然,如果有业务需求上传文件的大小更大的,需要同时修改Nginx配置及maxUploadSize配置,然后会报如下错误: 。。。。682 client intended to send too large body:。。。。。。。。。 至此,问题得以解决,真相大白于天下,由于是解决问题之后理解的,可能会有些遗漏,及忽略掉一些本人觉得没必要的其它的排查过程及说明,敬请见谅。
<property name="maxUploadSize" value="314572800" /> <!--300M-->
<property name="maxInMemorySize" value="314572800" /> <!--300M 设置multipart请求所允许的最大大小,默认不限制 -->
<property name="defaultEncoding" value="UTF-8"></property> <!-- 设置一个大小,multipart请求小于这个大小时会存到内存中,大于这个内存会存到硬盘中 -->
</bean>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。