AOP @Around:返回BAD_REQUEST响应

时间:2015-06-26 14:19:14

标签: spring aop spring-aop bad-request

在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();
        }
    }
}

5 个答案:

答案 0 :(得分:1)

您可以尝试返回响应实体

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

答案 1 :(得分:1)

有多种处理方式。

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

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

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

此外,您可以使用 ExceptionControllerAdvice 来处理 UnrecognizedPropertyException;您可以选择创建 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. 也可以在aspect的帮助下完成

     @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);
             }
         }
    

答案 2 :(得分:0)

您可以尝试使用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>
警告:没有经过测试,你可以用更清洁的方式实现过滤器

答案 3 :(得分:0)

您需要访问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();
    }
}

答案 4 :(得分:0)

我遇到了一个类似的问题,即暴露一个 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!"))
  }
}