Я добавляю ограничение скорости для спокойного webservice с использованием Spring MVC 4.1.советьте метод контроллера * перед обработкой @ @ Valid аннотации
Я создал аннотацию @RateLimited
, которую я могу применить к методам контроллера. A Spring AOP аспект перехватывает обращения к этим методам и генерирует исключение, если бы было слишком много запросов:
@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RateLimitingAspect {
@Autowired
private RateLimitService rateLimitService;
@Before("execution(* com.example..*.*(.., javax.servlet.ServletRequest+, ..)) " +
"&& @annotation(com.example.RateLimited)")
public void wait(JoinPoint jp) throws Throwable {
ServletRequest request =
Arrays
.stream(jp.getArgs())
.filter(Objects::nonNull)
.filter(arg -> ServletRequest.class.isAssignableFrom(arg.getClass()))
.map(ServletRequest.class::cast)
.findFirst()
.get();
String ip = request.getRemoteAddr();
int secondsToWait = rateLimitService.secondsUntilNextAllowedAttempt(ip);
if (secondsToWait > 0) {
throw new TooManyRequestsException(secondsToWait);
}
}
Это все работает отлично, за исключением того, когда метод @RateLimited
контроллер параметры помечаются как @Valid
, например:
@RateLimited
@RequestMapping(method = RequestMethod.POST)
public HttpEntity<?> createAccount(
HttpServletRequest request,
@Valid @RequestBody CreateAccountRequestDto dto) {
...
}
проблема: если проверка не пройдена, валидатор бросает MethodArgumentNotValidException
, который обрабатывается с помощью @ExceptionHandler
, который возвращает ошибочный ответ клиента, никогда не запускающий мой @Before
и, следовательно, обходя ограничивающую скорость.
Как я могу перехватить веб-запрос, подобный этому, таким образом, который имеет приоритет над проверкой параметров?
Я думал об использовании перехватчиков Spring или простых сервлетов Фильтры, но они сопоставляются простыми url-образцами, и мне нужно различать GET/POST/PUT/etc.
Это хорошая проблема. Интересно, что делает '@ RateLimited'. По умолчанию проверка поля с использованием '@ Valid' является болезненной в некоторых случаях. Возможно ли создать собственный 'Validator'. Я могу подумать о добавлении «Заголовок», чтобы отличить этот конкретный запрос. Но это добавит условную проверку для каждого запроса. Я попытался бы решить его на уровне метода, и если это не сработает, то подойдите к «перехватчику» –