0

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

我有一个暴露接口的 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 个。

我在这里面临的问题是,在编写了基于方面的 spring 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)() ;

4

1 回答 1

2

实际上,您向社区询问为什么您的建议不起作用,但没有发布实际的建议代码,这很有趣。所以我在这里要做的就是猜测。我能想到两件事:

  • 您的建议返回一个int,但原始代码返回一个String。实际上,@Around通知应该返回与包装/拦截方法(或)相同的类型Object
  • 您的通知调用proceed(),但您不希望执行原始方法并且不应该调用proceed(),而是返回您自己的结果。

无论如何,如果我的两个猜测是错误的,请更新您的问题,以便我可以更新我的答案,或者其他具有 CXF 知识的人(我没有,我是 AOP 专家)可以为您找到一种方法来做到这一点没有 AOP。

PS:还有一个问题:您是否测试过建议是否真的被触发了,例如通过在建议中写入日志消息?

于 2014-05-06T09:04:36.933 回答