【问题标题】:AOP @Around: return BAD_REQUEST responseAOP @Around:返回 BAD_REQUEST 响应
【发布时间】:2015-06-26 14:19:14
【问题描述】:

在 Spring REST 应用程序中,每个 URL 都必须以应用程序 id (appId) 开头。此 appId 必须在每个单独的休息服务中进行验证。我没有复制代码,而是尝试使用 @Around 建议创建 @Aspect。这是在任何休息方法之前正确执行的。

但是,如果应用程序 ID 未知,我既不想创建堆栈跟踪,也不想返回 200(响应 OK)。相反,我确实想返回一个 BAD_REQUEST 响应代码。

如果我在我的建议中抛出异常,我会得到一个堆栈跟踪并且没有 HTTP 响应。另一方面,如果我返回任何其他内容(但不调用 pjp.proceed),我会得到 200 的返回码。

谁能帮助我将响应代码 400 返回给请求者?

到目前为止,在我的代码下方:

@Component
@Aspect
public class RequestMappingInterceptor {

    @Autowired
    ListOfValuesLookupUtil listOfValuesLookupUtil;

    @Around("@annotation(requestMapping)")
    public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {
        Object[] arguments = pjp.getArgs();
        if(arguments.length == 0 || !listOfValuesLookupUtil.isValidApplication(arguments[0].toString())) {
            // toto : return bad request here ...
            throw new BadRequestException("Application id unknown!");
        } else {
            return pjp.proceed();
        }
    }
}

【问题讨论】:

  • 我是 AspectJ 专家,但不是 Spring MVC 专家。请为我提供更多坐标,并向我展示您想要拦截的一些方法签名(返回类型和参数)。您的请求映射方法是否实际上返回类似ResponseEntity<String> 的内容?我需要完整的图片才能回答。
  • 请在这个帖子中查看我的答案。我解释并提供示例代码stackoverflow.com/a/50712697/3073945

标签: spring aop spring-aop bad-request


【解决方案1】:

您需要访问HttpServletResponse 并使用它来发送错误代码。您可以通过RequestContextHolder 进行此操作

@Around("@annotation(requestMapping)")
public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {
    Object[] arguments = pjp.getArgs();
    if(arguments.length == 0 || !listOfValuesLookupUtil.isValidApplication(arguments[0].toString())) {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse());
        response.sendError(HttpStatus.PRECONDITION_FAILED.value(), "Application Id Unknown!");
        return null;
    } else {
        return pjp.proceed();
    }
}

【讨论】:

    【解决方案2】:

    您可以尝试返回响应实体

      if(arguments.length == 0 || !listOfValuesLookupUtil.isValidApplication(arguments[0].toString())) {
          return new ResponseEntity<>("Application id unknown!", HttpStatus.BAD_REQUEST);
      }else
    

    【讨论】:

    • Hmz,仍然得到一个 200 返回码,这很奇怪,因为我可以在调试模式下清楚地看到这个返回:java.lang.AssertionError:预期响应状态:400 实际:200
    【解决方案3】:

    有多种处理方式。

    1. 一种方法是在控制器参数级别使用 required = true。

      .. @RequestHeader(value = "something", required = true) final String something ..

    参考:@RequestHeader required property behavior for request paramter and value

    此外,您可以使用处理 UnrecognizedPropertyException 的 ExceptionControllerAdvice;或者,您可以创建 Error 对象以获得更好的响应方法。

    例子

    @RestControllerAdvice
    public class ExceptionControllerAdvice {
    
        @ExceptionHandler(value = UnrecognizedPropertyException.class)
        public ResponseEntity<Error> handle(@Nonnull final UnrecognizedPropertyException exception) {
            final Error error = new Error();
            error.setMessage(exception.getOriginalMessage());
            error.setField(exception.getPropertyName());
            error.setType(HttpStatus.BAD_REQUEST.name());
            return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    
        }
    }
    

    或者,如果你只是想返回字符串

    @ExceptionHandler(value = UnrecognizedPropertyException.class)
    public ResponseEntity<String> handle(@Nonnull final UnrecognizedPropertyException exception) {
        // If you don't want to use default message just use "Application Id Unknown!" instead of exception.getOriginalMessage()
        return new ResponseEntity<>(exception.getOriginalMessage(), HttpStatus.BAD_REQUEST);
    }
    
    1. 也可以借助方面来完成

       @Component
       @Aspect
       public class RequestMappingInterceptor {
       @Autowired
       ListOfValuesLookupUtil listOfValuesLookupUtil;
      
       @Around("@annotation(requestMapping)")
       public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {
           Object[] arguments = pjp.getArgs();
           if(arguments.length == 0 || !listOfValuesLookupUtil.isValidApplication(arguments[0].toString())) {
               // toto : return bad request here ...
               throw new BadRequestException("Application id unknown!");
           } else {
               return pjp.proceed();
           }
       }
      }
      

      您需要在控制器或 ExceptionControllerAdvice 中处理 BadRequestExcption

       @RestControllerAdvice
           public class ExceptionControllerAdvice {
      
               @ExceptionHandler(value = BadRequestExcption.class)
               public ResponseEntity<Error> handle(@Nonnull final BadRequestExcption exception) {
                   return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
               }
           }
      

    【讨论】:

      【解决方案4】:

      我遇到了一个类似的问题,即暴露 Single 的 rest api。最后对我有用的是:

      @Component
      @Aspect
      public class RequestMappingInterceptor {
      
        @Around("@annotation(validRequest)")
        public Object around(ProceedingJoinPoint pjp, ValidRequest validRequest) throws Throwable {
          Object[] arguments = pjp.getArgs();
          Boolean flag = validationMethod(arguments, validRequest);
          return flag ? pjp.proceed() : Single.error(new BadRequestException("Value is invalid!"))
        }
      } 
      

      【讨论】:

        【解决方案5】:

        您可以尝试使用 OncePerRequestFilter 而不是 Aspect。

        创建一个过滤器类

        public class URLFilter extends OncePerRequestFilter {
        
          @Override
          protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
          FilterChain filterChain) throws ServletException, IOException {
            if(!request.getRequestURL().toString().contains("appId") { 
              response.setStatus(401);
              return;
            }
            filterChain.doFilter(request, response);
          }
        

        在你的配置中为你的过滤器创建一个 Spring bean(或使用@Component)

        <bean id="urlFilter" class="com.xyz.filter.URLFilter" />
        

        然后将过滤器添加到您的 web.xml

        <filter>
            <filter-name>urlFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
        
        <filter-mapping>
            <filter-name>urlFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        

        警告:未经测试,您可能可以以更简洁的方式实现过滤器

        【讨论】:

          猜你喜欢
          • 2022-08-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-29
          • 1970-01-01
          • 1970-01-01
          • 2012-07-11
          • 1970-01-01
          相关资源
          最近更新 更多