为了减轻服务器(CPU/内存/网络带宽)负荷,避免DDoS攻击,必须限制客户端的文件上传大小。
常用兆和字节对应表:
[quote] 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[/quote]
一般请求的处理流是:客户端 -> Web服务器 -> Web容器 -> 框架。
所以在任何一个环节都可以对文件大小进行限制。
[b](1)客户端限制[/b]
常用的开源文件上传组件都可以限制文件大小。
jQuery-File-Upload:maxFileSize
[url=https://github.com/blueimp/jQuery-File-Upload/wiki/Options]https://github.com/blueimp/jQuery-File-Upload/wiki/Options[/url]
plupload:max_file_size
[url=https://github.com/moxiecode/plupload/wiki/Options#filters.max_file_size]https://github.com/moxiecode/plupload/wiki/Options#filters.max_file_size[/url]
Dropzone:maxFilesize
[url=http://www.dropzonejs.com/#config-maxFilesize]http://www.dropzonejs.com/#config-maxFilesize[/url]
FineUploader:sizeLimit
[url=https://docs.fineuploader.com/features/validation.html]https://docs.fineuploader.com/features/validation.html[/url]
[b](2)Web服务器限制[/b]
[b]Nginx:client_max_body_size(ngnix.conf)[/b]
[url=http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size]http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size[/url]
默认是1MB,超过后直接返回413 (Request Entity Too Large) 。设置为0时表示无限制。
[b]Apache:LimitRequestBody(.htaccess)[/b]
[url=https://httpd.apache.org/docs/2.4/en/mod/core.html#limitrequestbody]https://httpd.apache.org/docs/2.4/en/mod/core.html#limitrequestbody[/url]
默认为0(无限制),可以指定0到2GB的数值。
[b]PHP:upload_max_filesize(php.ini)[/b]
[quote]memory_limit = 40M
post_max_size = 32M
upload_max_filesize = 32M[/quote]
[b](3)Web容器限制[/b]
[b]Tomcat连接器:maxPostSize(server.xml)[/b]
[url=http://tomcat.apache.org/tomcat-8.5-doc/config/ajp.html]http://tomcat.apache.org/tomcat-8.5-doc/config/ajp.html[/url]
[url=http://tomcat.apache.org/tomcat-8.5-doc/config/http.html]http://tomcat.apache.org/tomcat-8.5-doc/config/http.html[/url]
默认是2MB。设置为0时表示无限制。
[b]Servlet 3.0:multipart-config(web.xml)[/b]
或Servlet类注解:
[b](4)框架限制[/b]
[b]SpringBoot设置:[/b]
[b]Java配置[/b]
默认采用StandardServletMultipartResolver ,所以上边的定义和Servlet 3.0的定义是一致的。也可以采用CommonsMultipartResolver。
[b]Apache Commons Upload设置:[/b]
[color=blue][b]文件大小限制后,超大文件如何上传?[/b][/color]
[url=http://rensanning.iteye.com/blog/2248760]Spring MVC大文件的断点续传[/url] 这篇文章说的是如何下载大文件,和如何上传大文件很类似,把大文件分割成小的chunks逐个上传。需要的是浏览器端和服务器端都支持才行。
[b]浏览器[/b]
如果浏览器自身支持的话,大多数开源组件都能做分割上传,
比如jQuery-File-Upload可以指定maxChunkSize参数:[url=https://github.com/blueimp/jQuery-File-Upload/wiki/Chunked-file-uploads]https://github.com/blueimp/jQuery-File-Upload/wiki/Chunked-file-uploads[/url]
[b]服务器[/b]
接收文件数据时就需要特殊处理一下。
- 根据HTTP头部是否有Content-Range参数分成两个不同方法
- 如果是Chunk上传的话,第一次为创建文件,之后皆是往文件中追加内容
常用兆和字节对应表:
[quote] 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[/quote]
一般请求的处理流是:客户端 -> Web服务器 -> Web容器 -> 框架。
所以在任何一个环节都可以对文件大小进行限制。
[b](1)客户端限制[/b]
常用的开源文件上传组件都可以限制文件大小。
jQuery-File-Upload:maxFileSize
[url=https://github.com/blueimp/jQuery-File-Upload/wiki/Options]https://github.com/blueimp/jQuery-File-Upload/wiki/Options[/url]
plupload:max_file_size
[url=https://github.com/moxiecode/plupload/wiki/Options#filters.max_file_size]https://github.com/moxiecode/plupload/wiki/Options#filters.max_file_size[/url]
Dropzone:maxFilesize
[url=http://www.dropzonejs.com/#config-maxFilesize]http://www.dropzonejs.com/#config-maxFilesize[/url]
FineUploader:sizeLimit
[url=https://docs.fineuploader.com/features/validation.html]https://docs.fineuploader.com/features/validation.html[/url]
[b](2)Web服务器限制[/b]
[b]Nginx:client_max_body_size(ngnix.conf)[/b]
[url=http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size]http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size[/url]
默认是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;
}
}
[b]Apache:LimitRequestBody(.htaccess)[/b]
[url=https://httpd.apache.org/docs/2.4/en/mod/core.html#limitrequestbody]https://httpd.apache.org/docs/2.4/en/mod/core.html#limitrequestbody[/url]
默认为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>
[b]PHP:upload_max_filesize(php.ini)[/b]
[quote]memory_limit = 40M
post_max_size = 32M
upload_max_filesize = 32M[/quote]
[b](3)Web容器限制[/b]
[b]Tomcat连接器:maxPostSize(server.xml)[/b]
[url=http://tomcat.apache.org/tomcat-8.5-doc/config/ajp.html]http://tomcat.apache.org/tomcat-8.5-doc/config/ajp.html[/url]
[url=http://tomcat.apache.org/tomcat-8.5-doc/config/http.html]http://tomcat.apache.org/tomcat-8.5-doc/config/http.html[/url]
默认是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
[b]Servlet 3.0:multipart-config(web.xml)[/b]
<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
)
[b](4)框架限制[/b]
[b]SpringBoot设置:[/b]
#application.properties
spring.http.multipart.max-file-size=5MB
spring.http.multipart.max-request-size=10MB
[b]Java配置[/b]
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setMaxFileSize("5MB");
factory.setMaxRequestSize("10MB");
return factory.createMultipartConfig();
}
默认采用StandardServletMultipartResolver ,所以上边的定义和Servlet 3.0的定义是一致的。也可以采用CommonsMultipartResolver。
[b]Apache Commons Upload设置:[/b]
@Bean
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver cmr = new CommonsMultipartResolver();
cmr.setMaxUploadSize(10485760);
cmr.setMaxUploadSizePerFile(5242880);
return cmr;
}
[color=blue][b]文件大小限制后,超大文件如何上传?[/b][/color]
[url=http://rensanning.iteye.com/blog/2248760]Spring MVC大文件的断点续传[/url] 这篇文章说的是如何下载大文件,和如何上传大文件很类似,把大文件分割成小的chunks逐个上传。需要的是浏览器端和服务器端都支持才行。
[b]浏览器[/b]
如果浏览器自身支持的话,大多数开源组件都能做分割上传,
比如jQuery-File-Upload可以指定maxChunkSize参数:[url=https://github.com/blueimp/jQuery-File-Upload/wiki/Chunked-file-uploads]https://github.com/blueimp/jQuery-File-Upload/wiki/Chunked-file-uploads[/url]
$(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
});
});
[b]服务器[/b]
接收文件数据时就需要特殊处理一下。
- 根据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;
}
}