如何限制Spring Boot API禁止传入重复查询参数?
处理Spring Boot中重复查询参数的400错误返回
方案一:自定义校验注解(推荐,符合注解实现需求)
这种方式可以精准控制哪些参数需要校验重复,步骤如下:
- 定义自定义校验注解
@NoDuplicateParam
import jakarta.validation.Constraint; import jakarta.validation.Payload; import java.lang.annotation.*; @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = NoDuplicateParamValidator.class) public @interface NoDuplicateParam { String message() default "重复的查询参数不被允许"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
- 实现对应的校验器
NoDuplicateParamValidator
import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; public class NoDuplicateParamValidator implements ConstraintValidator<NoDuplicateParam, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes == null) return true; HttpServletRequest request = attributes.getRequest(); String paramName = context.getPropertyName(); String[] paramValues = request.getParameterValues(paramName); return paramValues == null || paramValues.length <= 1; } }
- 在控制器中使用注解,记得开启方法级校验
import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @Validated // 必须添加此注解启用参数校验 public class MyApiController { @GetMapping("/my-api") public String myApi(@NoDuplicateParam @RequestParam String foo) { return foo; } }
- 配置全局异常处理器,捕获校验异常返回400
import jakarta.validation.ConstraintViolationException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) { FieldError error = ex.getBindingResult().getFieldError(); String message = error != null ? error.getDefaultMessage() : "参数校验失败"; return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST); } @ExceptionHandler(ConstraintViolationException.class) public ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException ex) { String message = ex.getConstraintViolations().stream() .map(violation -> violation.getMessage()) .findFirst() .orElse("参数校验失败"); return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST); } }
方案二:全局过滤器拦截所有重复参数
如果需要所有接口都禁止重复查询参数,可以写一个过滤器在请求到达控制器前拦截:
import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.Enumeration; @Component public class DuplicateParamFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; Enumeration<String> paramNames = httpRequest.getParameterNames(); boolean hasDuplicate = false; String duplicateParam = ""; while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); String[] values = httpRequest.getParameterValues(paramName); if (values != null && values.length > 1) { hasDuplicate = true; duplicateParam = paramName; break; } } if (hasDuplicate) { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST); httpResponse.getWriter().write("参数 " + duplicateParam + " 不允许重复"); return; } chain.doFilter(request, response); } }
方案三:修改Spring参数解析逻辑
通过自定义参数解析器,替换默认的RequestParamMethodArgumentResolver,当发现参数有多个值时直接抛出异常:
- 自定义参数解析器
import jakarta.servlet.http.HttpServletRequest; import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.mvc.method.annotation.RequestParamMethodArgumentResolver; public class NoDuplicateRequestParamResolver extends RequestParamMethodArgumentResolver { public NoDuplicateRequestParamResolver(boolean useDefaultResolution) { super(useDefaultResolution); } @Override protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { HttpServletRequest httpRequest = request.getNativeRequest(HttpServletRequest.class); if (httpRequest != null) { String[] values = httpRequest.getParameterValues(name); if (values != null && values.length > 1) { throw new IllegalArgumentException("参数 " + name + " 不允许重复"); } } return super.resolveName(name, parameter, request); } }
- 注册解析器到Spring容器
import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new NoDuplicateRequestParamResolver(true)); } }
- 全局异常处理器添加
IllegalArgumentException捕获
在之前的GlobalExceptionHandler中新增:
@ExceptionHandler(IllegalArgumentException.class) public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST); }
内容的提问来源于stack exchange,提问作者Brunke
相关产品推荐
相关产品推荐

