常用兆和字节对应表:
引用
1 MB = 1048576 B
2 MB = 2097152 B
5 MB = 5242880 B
10 MB = 10485760 B
20 MB = 20971520 B
50 MB = 52428800 B
100 MB = 104857600 B
200 MB = 209715200 B
2 MB = 2097152 B
5 MB = 5242880 B
10 MB = 10485760 B
20 MB = 20971520 B
50 MB = 52428800 B
100 MB = 104857600 B
200 MB = 209715200 B
一般请求的处理流是:客户端 -> Web服务器 -> Web容器 -> 框架。
所以在任何一个环节都可以对文件大小进行限制。
(1)客户端限制
常用的开源文件上传组件都可以限制文件大小。
jQuery-File-Upload:maxFileSize
https://github.com/blueimp/jQuery-File-Upload/wiki/Options
plupload:max_file_size
https://github.com/moxiecode/plupload/wiki/Options#filters.max_file_size
Dropzone:maxFilesize
http://www.dropzonejs.com/#config-maxFilesize
FineUploader:sizeLimit
https://docs.fineuploader.com/features/validation.html
(2)Web服务器限制
Nginx:client_max_body_size(ngnix.conf)
http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size
默认是1MB,超过后直接返回413 (Request Entity Too Large) 。设置为0时表示无限制。
server { client_max_body_size 1m; location /users/profile/edit/avatar { client_max_body_size 2m; } location /users/profile/edit/images { client_max_body_size 5m; } }
Apache:LimitRequestBody(.htaccess)
https://httpd.apache.org/docs/2.4/en/mod/core.html#limitrequestbody
默认为0(无限制),可以指定0到2GB的数值。
<VirtualHost *:8000> <Location /> LimitRequestBody 1048576 </Location> <Location /users/profile/edit/avatar> LimitRequestBody 2097152 </Location> <Location /users/profile/edit/images> LimitRequestBody 5242880 </Location> </VirtualHost>
PHP:upload_max_filesize(php.ini)
引用
memory_limit = 40M
post_max_size = 32M
upload_max_filesize = 32M
post_max_size = 32M
upload_max_filesize = 32M
(3)Web容器限制
Tomcat连接器:maxPostSize(server.xml)
http://tomcat.apache.org/tomcat-8.5-doc/config/ajp.html
http://tomcat.apache.org/tomcat-8.5-doc/config/http.html
默认是2MB。设置为0时表示无限制。
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" maxPostSize="10485760" /> <-10MB
<Connector port="8080" protocol="HTTP/1.1" redirectPort="8443" maxPostSize="10485760"/> <-10MB
Servlet 3.0:multipart-config(web.xml)
<multipart-config> <location>/tmp</location> <max-file-size>5242880</max-file-size> <max-request-size>10485760</max-request-size> <file-size-threshold>32768</file-size-threshold> </multipart-config>
或Servlet类注解:
@MultipartConfig( location="/tmp", maxFileSize=5242880, maxRequestSize=10485760, fileSizeThreshold=32768 )
(4)框架限制
SpringBoot设置:
#application.properties spring.http.multipart.max-file-size=5MB spring.http.multipart.max-request-size=10MB
Java配置
@Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setMaxFileSize("5MB"); factory.setMaxRequestSize("10MB"); return factory.createMultipartConfig(); }
默认采用StandardServletMultipartResolver ,所以上边的定义和Servlet 3.0的定义是一致的。也可以采用CommonsMultipartResolver。
Apache Commons Upload设置:
@Bean public CommonsMultipartResolver multipartResolver() { CommonsMultipartResolver cmr = new CommonsMultipartResolver(); cmr.setMaxUploadSize(10485760); cmr.setMaxUploadSizePerFile(5242880); return cmr; }
文件大小限制后,超大文件如何上传?
Spring MVC大文件的断点续传 这篇文章说的是如何下载大文件,和如何上传大文件很类似,把大文件分割成小的chunks逐个上传。需要的是浏览器端和服务器端都支持才行。
浏览器
如果浏览器自身支持的话,大多数开源组件都能做分割上传,
比如jQuery-File-Upload可以指定maxChunkSize参数: https://github.com/blueimp/jQuery-File-Upload/wiki/Chunked-file-uploads
$(function () { $('#upload').fileupload({ url: 'http://localhost:8080/upload', type: "POST", dataType: 'json', singleFileUploads: true, autoUpload: true }); $('#uploadChunked').fileupload({ url: 'http://localhost:8080/upload', type: "POST", dataType: 'json', singleFileUploads: true, autoUpload: true, maxChunkSize: 1048576 }); });
服务器
接收文件数据时就需要特殊处理一下。
- 根据HTTP头部是否有Content-Range参数分成两个不同方法
- 如果是Chunk上传的话,第一次为创建文件,之后皆是往文件中追加内容
@RestController public class UploadController { private static final String FILE_DIR = "d:\\"; private static final Pattern RANGE_PATTERN = Pattern.compile("bytes ([0-9]+)-([0-9]+)/([0-9]+)"); @PostMapping(value = "/upload", headers = "!Content-Range") public Map<String, String> uploadMultipart(@RequestParam("file") final MultipartFile file, HttpServletResponse res) throws Exception { String fileName = file.getOriginalFilename(); File source = new File(FILE_DIR + fileName); file.transferTo(source); Map<String, String> result = new HashMap<String, String>(); result.put("name", FILE_DIR + fileName); return result; } @PostMapping(value = "/upload", headers = "Content-Range") public Map<String, String> uploadChunked(HttpServletRequest req, HttpServletResponse res) throws Exception { String contentRange = req.getHeader("Content-Range"); String begin = ""; Matcher matcher2 = RANGE_PATTERN.matcher(contentRange); if (matcher2.matches()) { begin = matcher2.group(1); } MultipartHttpServletRequest multiReq = (MultipartHttpServletRequest) req; MultipartFile f = multiReq.getFile("file"); String fileName = f.getOriginalFilename(); if ("0".equals(begin)) { File source = new File(FILE_DIR + fileName); f.transferTo(source); } else { Path file = Paths.get(FILE_DIR, fileName); Files.write(file, f.getBytes(), StandardOpenOption.APPEND); } Map<String, String> result = new HashMap<String, String>(); result.put("name", FILE_DIR + fileName); return result; } }