基于Aspect从Spring AOP返回HTTP状态400

时间:2014-05-06 03:07:27

标签: annotations aop interceptor http-status-code-400 aspect

我对我有一个有趣的问题(至少从我目前的观点来看这是一个问题)。

我有一个暴露界面的RESTful Web服务。在我们的环境中,我们使用注释来装饰请求处理程序,例如 -

@RequiredTokenType("Binary")
public String getRecordInfo(HttpServletRequest request) {
    String recordInfo = null;

    final String methodName = "getRecordInfo()";
    _log.debug("{}: received request", methodName);

    // validate the request information
    ValidationUtils.validateAcceptHeader(request, MimeConstants.getContentType());

    .   .   .
    .   .   .

    return recordInfo;
}

我们需要在处理程序之前执行一个CXF拦截器/方面(spring AOP)(如上所述),并检查HttpServletRequest是否有令牌类型。如果令牌类型(或装饰处理程序的任何其他属性)不是注释中指定的类型,则停止执行并返回HTTP状态400(错误请求)。有大约20个请求处理程序,如上所述。

我在这里遇到的问题是在编写基于方面的弹簧AOP之后(如下所示)我能够在getRecordInfo()执行之前捕获请求,但是当我尝试返回400(或)抛出异常时,HTTP客户端仍然看到200 -

public void validateRequest(ProceedingJoinPoint joinPoint,
                            HttpServletRequest httpRequest,
                            RequiredTokenType tokenType) throws Throwable {

    final String methodName = "validateRequest()";
    _logger.info("{}: Entered, Thread Id: {}", methodName, "" + Thread.currentThread().getId());

    // Extract the *REQUIRED* headers from the request ...
    final String tokenData = httpRequest.getHeader(HEADER_TOKEN_DATA);

    if (tokenData == null || tokenData.trim().length() < MIN_POSSIBLE_TOKEN_SIZE) {
        // Error condition .... return (400 Bad Request)
        _logger.info("{}: Invalid token. The HTTP request is rejected in lack of a valid token.");

        throw new MissingTokenException(HttpStatus.BAD_REQUEST,
                                        ErrorCode.BAD_REQUEST,
                                        "Token is missing from the request.");
    }

    ValidityToken extractedTokenFromRequest = ValidityToken.initializeFromBase64(tokenData);

    // Get the type of the token this request must include ...
    String decoratedTokenType = tokenType.value();
    _logger.debug("{}: Token Type Required: ", methodName, decoratedTokenType);

    if (! extractedTokenFromRequest.getTypeName().equals(decoratedTokenType)) {
        // Error condition .... return (400).
        _logger.info("{}: {}",
                     methodName,
                     "The token in the request mismatches the type specified in RequiredTokenType handler. 400 Bad Request.");
        throw new TokenTypeMismatchException(HttpStatus.BAD_REQUEST,
                                             ErrorCode.BAD_REQUEST,
                                             "Token type doesn't match.");
    }

    // More validations on extractedTokenFromRequest
    .   .   .
    .   .   .

    // Continue with the actual business logic if correct token is included ...
    joinPoint.proceed();
}

我检查了日志文件,我可以看到以下日志条目,确认请求处理程序和方面都被调用 -

    getRecordInfo(): received request
    .   .   .
    .   .   .
    validateRequest(): Entered, Thread Id: 792
    .   .   .
    .   .   .
    validateRequest(): Invalid token. The HTTP request is rejected in lack of a valid token.

尽管有消息,仍然客户端看到200和服务器日志显示其他基于CXF的拦截器正在执行的证据。

以下是定义切入点的Spring上下文XML -

<bean id="vGateKeeper" class="com....core.RequestValidator" />


<aop:config>
    <aop:aspect id="methodInvocation" ref="methodInvocationProfiler">
        <aop:around method="profileMethodInvocation"
                    pointcut="execution(* org.springframework.orm.jpa.JpaTransactionManager.commit(..))"/>
        <aop:around method="profileMethodInvocation"
                    pointcut="execution(* org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(..))"/>
    </aop:aspect>
    <aop:aspect id="gateKeeper" ref="vGateKeeper">
        <aop:pointcut expression="execution(* getRecordInfo(..)) and args(httpRequest) and @annotation(modPerms)" id="my"/>
        <aop:around pointcut-ref="my" method="validateRequest"/>
    </aop:aspect>
</aop:config>

在这种情况下,如何使用Spring AOP方面返回HTTP 400,取消执行任何其他拦截器?

我还在编写一个Apache CXF拦截器来捕获调用并在它到达请求处理程序之前返回400,但后来我不确定,如何使用拦截器我可以知道哪个请求处理程序是假设执行的什么注释正在装饰请求处理程序。 CXF拦截器是否提供任何方式来知道哪个请求处理程序最终会执行?

我在这里看,(https://cxf.apache.org/docs/interceptors.html),但无论如何都没找到。

感谢任何帮助。

此致

(* Vipul)();

1 个答案:

答案 0 :(得分:1)

实际上,你问社区为什么你的建议不起作用,但不发布实际的建议代码是相当有趣的。所以我在这里留下的只是猜测。我可以想到两件事:

  • 您的建议会返回int,但原始代码会返回String。实际上,@Around建议应该返回与包装/截获方法相同的类型(或Object)。
  • 您的建议致电proceed(),但您不希望执行原始方法,也不应该致电proceed(),而是返回您自己的结果。

在任何情况下,如果我的两个猜测是错误的,请更新您的问题,以便我可以更新我的答案或其他具有CXF知识的人(我没有,我是AOP专家)可以为您找到一个方法没有AOP就可以做到。

P.S。:还有一个问题:您是否测试了该建议是否实际被解雇,例如:通过在建议中写日志消息?