当前位置: 首页 > 知识库问答 >
问题:

在处理*@有效注释之前,建议控制器方法*

易星宇
2023-03-14

我正在使用Spring MVC 4.1为restful Web服务添加速率限制。

我创建了一个@RateLimited注释,可以应用于控制器方法。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) {

...
}

问题:如果验证失败,验证器会抛出由@ExceptionHandler处理的MultiodArgumentNotValidExc0019,它会向客户端返回错误响应,永远不会触发我的@之前,因此绕过速率限制。

如何以优先于参数校验的方式拦截这样的Web请求?

我曾想过使用Spring拦截器或普通servlet过滤器,但它们是通过简单的url模式映射的,我需要通过GET/POST/PUT/etc进行区分。

共有2个答案

史鹏云
2023-03-14

看看是否可以为@posthrowing建议实现类似的逻辑,这些建议将具有类似的切入点。

苏承载
2023-03-14

我最终放弃了寻找AOP解决方案的尝试,转而创建了一个Spring Interceptor。拦截器preHandle的所有请求,并监视其处理程序为@RateLimited的请求。

@Component
public class RateLimitingInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private final RateLimitService rateLimitService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (HandlerMethod.class.isAssignableFrom(handler.getClass())) {
            rateLimit(request, (HandlerMethod)handler);
        }
        return super.preHandle(request, response, handler);
    }

    private void rateLimit(HttpServletRequest request, HandlerMethod handlerMethod) throws TooManyRequestsException {

        if (handlerMethod.getMethodAnnotation(RateLimited.class) != null) {
            String ip = request.getRemoteAddr();
            int secondsToWait = rateLimitService.secondsUntilNextAllowedInvocation(ip);
            if (secondsToWait > 0) {
                throw new TooManyRequestsException(secondsToWait);
            } else {
                rateLimitService.recordInvocation(ip);
            }
        }
    }
}
 类似资料:
  • 我的rest控制器包含以下post映射: ServiceExceptionn是特定于我的应用程序的自定义异常。 控制器建议如下所示: 应用yml包含以下属性: 如果我使用大小大于2MB的文件调用rest api,则会出现以下异常: 我在这里面临的问题是:控制器的建议没有按照预期工作。handleFileTooLargeException-必须执行此方法,因为它使用特定异常类型中提到的Excepti

  • 问题内容: 我试图在带注释的控制器之后使用AOP进行一些处理。一切都在正常运行,但没有执行建议。 这是控制器代码: 以及在application-config中的设置 和实际的建议 甚至可以对带注释的控制器提出建议吗?我正在使用Spring 2.5。 问题答案: 我假设你想在用注释的类中执行所有方法后提出建议@Controller。 这是一个例子: 如果你想将Spring AOP与AspectJ语

  • 我的Spring Boot应用程序中有一系列Rest API控制器,其请求映射与某些URL匹配。我需要更改我的实现,以始终确保为所有请求设置特定的自定义标头。如果标头不在那里,我想使请求失败。如果是这样,我想转发到适当的控制器,这将与我当前的实现相同。 有没有办法在Spring Boot做到这一点,而无需修改我现有的控制器呢?我可以尝试使用类似Spring Security的东西吗,即使我的头与安

  • 需要注释处理器的帮助。我创建了一个简单的注释处理器,它使用@autoservice注释来检查注释的字段是否为最终字段。但它没有显示任何编译时错误。这是我的配置 注释: 注释处理器: pom文件: 测试文件:

  • 在我尝试构建我的项目后,我得到以下错误: 我尝试在每个之后添加,但没有成功消除错误。 这是在将Android Studio升级到最新版本 ( 3.0 ) 之后发生的。 编辑: 在中添加 无济于事: 有什么解决方案吗?

  • 我有以下问题: 我已经为安全性创建了注释: 在我具有类之间的继承性的情况下,是否也有可能所有类都具有@Security注释来获得最具体的定义? 约西