如何限制每个端点或控制器的MultipartFile大小(非全局)



我想为每个端点或每个控制器设置一个唯一的文件大小限制。

我知道我可以用以下属性设置全局文件大小限制,但这不是我想做的,我想要每个端点或控制器的唯一限制:

spring:
servlet:
multipart:
max-file-size: 1MB
max-request-size: 1MB

我已经创建了一个自定义验证器,但这还不够好,我想防止用户调用端点,而不是丢弃太大的文件,我想阻止上传。

public class LogoValidator implements ConstraintValidator<ValidLogo, MultipartFile> {
private static final String[] validLogoTypes = new String[]{"image/jpg", "image/jpeg", "image/png", "image/svg"};
private static final long MAX_LOGO_SIZE = 1024L * 1024L;
@Override
public boolean isValid(MultipartFile file, ConstraintValidatorContext context) {
if (file.getSize() > MAX_LOGO_SIZE) {
return false;
}
for(String type : validLogoTypes) {
if (type.equals(file.getContentType())) return true;
}
return false;
}
}
@Documented
@Constraint(validatedBy = LogoValidator.class)
@Target( {ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidLogo {
String message() default "Invalid logo.";
}

您可以尝试使用Servlet过滤器进行同样的操作。由于您使用的是spring,OncePerRequestFilter可能是一个不错的选择。

https://www.baeldung.com/spring-onceperrequestfilter

在筛选器中,您可以绑定每个端点的大小。有多种方法可以做到这一点例如:您可以通过配置yaml进行配置。

endpoints:
/some/endpt: 
supported-types: yaml,image
max-size:300
/some/other/endpt: 
supported-types:image
max-size:300

使用configurationproperties将其连接到类https://www.baeldung.com/configuration-properties-in-spring-boot#nested-属性

Initialize at start of filter 
Map<String,String> endpointMap = new HashMap<>();
endpointMap.putAll(fromSpringconfigurationpropertiesmap)
//use request.getUrl() or request.getServletPath() based on your requirement to get url
endpointMap.get("urlFromRequest"); // can return url+ supported types.
//reject if size and supported type does not match logic here...

希望能有所帮助。

根据swapyonobuntu提供的提示,创建一个bean来注册一个新的过滤器。然后注册你的过滤器,如果这个特定的过滤器只用于一两个非常特定的端点,那么也可以内联实现。

@Configuration
public class LogoFilterConfig {
private static final List<String> VALID_LOGO_TYPES = Arrays.asList(
"image/jpeg", "image/jpg", "image/svg", "image/png"
);
private static final long MAX_IMG_SIZE = 2000000;
@Bean
public FilterRegistrationBean<Filter> logoFilter(){
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new OncePerRequestFilter() {
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain
) throws ServletException, IOException {
if (!VALID_LOGO_TYPES.contains(request.getPart("logo").getContentType())) {
response.sendError(HttpStatus.BAD_REQUEST.value(), "Unsupported media type.");
return;
/*
Returning here means the req/resp is never added to filterChain.

The 'response' is returned to the consumer in its current state, 
therefore it's best to modify it for better ux.
*/
}
if (request.getPart("logo").getSize() > MAX_IMG_SIZE) {
response.sendError(HttpStatus.BAD_REQUEST.value(), "Logo too large, max allowed 2MB.");
return;
}
/*
Counterintuitively adding to the filter chain is how you allow the request to go through.
*/
filterChain.doFilter(request, response);
}
});
registrationBean.addUrlPatterns("/my/logo");
registrationBean.setOrder(2);
return registrationBean;
}
}

最新更新