使用Spring AOP捕获Http状态代码的正确方法是什么?

我正在创建一个方面来使用org.springframework.web.bind.annotation.RestController之类的@Pointcut来注册我的应用程序,当我的类正常响应时,这种方法非常有效,但是由于某种原因发生异常时,返回的httpStatus始终为200,即使我的http响应在发生错误时返回500,我也认为这是因为RestController不会设置http状态,而是将其委托给异常处理程序,我该如何解决这个问题,并且在restcontroller上仍然具有可追溯性? >

跟随我的休息控制器

@Slf4j
@RestController
@RequestMapping("/api/conta")
public class ContaResourceHTTP {


    @JetpackMethod("Pagamento de conta")
    @PostMapping("/pagamento")
    public void realizarPagamento(@RequestBody DTOPagamento dtoPagamento) throws InterruptedException
    {

    }

    @JetpackMethod("Transferência entre bancos")
    @PostMapping("/ted")
    public void realizarTED(@RequestBody DTOPagamento dtoPagamento) throws java.lang.Exception
    {
        if(true)
            throw new Exception("XXX");
        //log.info(dtoPagamento.toString());
    }

}

我的AOP实现:

@Aspect
@Component
@EnableAspectJAutoProxy(proxyTargetclass = true)
@Slf4j
public class MetricsAspect {

    //@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    @Pointcut("execution(* javax.servlet.http.HttpServlet.*(..)) *)")
    public void springBeanPointcut() {
    }

    @Autowired
    Tracer tracer;

    @Around("springBeanPointcut()")
    public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest();

        long inicioProcesso = System.currentTimeMillis();

        joinPoint.proceed();

        long finalProcesso = System.currentTimeMillis();

        long duracaoProcesso = finalProcesso - inicioProcesso;

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        Metrics metricas = new Metrics();

        metricas.setDuracaoMs(duracaoProcesso);
        metricas.setDataHoraRequisicao(milissegundosToStringDate(inicioProcesso));
        metricas.setDataHoraResposta(milissegundosToStringDate(finalProcesso));
        metricas.setServidorOrigem(request.getRemoteAddr());
        metricas.setPortaOrigem(request.getRemotePort());
        metricas.setDominioAcesso(request.getLocalName());
        metricas.setPortaAcesso(request.getLocalPort());
        metricas.setUrlPath(request.getRequesturi());
        metricas.setMetodoHttp(request.getMethod());
        metricas.setIdTransacao(tracer.currentSpan().context().traceIdString());
        metricas.setIdSpan(tracer.currentSpan().context().spanIdString());
        metricas.setStatusHttp(response.getStatus());

        log.info(JSONConversor.toJSON(metricas));

    }

    public String milissegundosToStringDate(long ms) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

        Date dataInicial = new Date(ms);

        return dateFormat.format(dataInicial);
    }
}

我的异常处理程序:

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ExceptionControllerAdvice {


    @ExceptionHandler({ Throwable.class })
    public ResponseEntity<ApiError> handlerValidationException2(Throwable e) {
        return new ResponseEntity<>(new ApiError(HttpStatus.INTERNAL_SERVER_ERROR,e,traceRespostaAPI),HttpStatus.INTERNAL_SERVER_ERROR);
    }


}
a12473740 回答:使用Spring AOP捕获Http状态代码的正确方法是什么?

过了一会儿,我用一个可能不是最优雅的解决方案解决了这个问题,基本上我使用了两个切入点,一个在restcontroller中来拦截@JetpackMethod批注值并将其添加到http响应标头,上面有关于HttpServlet的建议,实际上是真正返回修改后的http状态的人。

下面的代码解决了我的问题。

此类拦截注释并将其值添加到标题中。

@Aspect
@Component
public class InterceptRestAnnotationAspect {

    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void restControllerExecution() {}


    @Before("restControllerExecution()")
    public void setMetodoHttpHeader(JoinPoint joinPoint) throws Throwable {

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        String origem = VerificadorOrigem.processarOrigem(joinPoint);

        response.setHeader("nomeMetodo",origem);

    }

}

另一个类记录了我需要的servlet指标,并且可以检索之前在标头中输入的值。

@Aspect
@Component
@Slf4j
public class MetricsAspect {

    @Pointcut("execution(* javax.servlet.http.HttpServlet.*(..)) *)")
    public void servletService() {
    }

    @Autowired
    Tracer tracer;

    @Around("servletService()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest();

        long inicioProcesso = System.currentTimeMillis();

        Object result = joinPoint.proceed();

        long finalProcesso = System.currentTimeMillis();

        long duracaoProcesso = finalProcesso - inicioProcesso;

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        Metrics metricas = new Metrics();

        String funcionalidade = response.getHeader("nomeMetodo") == null ? "Indeterminada"
                : response.getHeader("nomeMetodo");

        metricas.setNivelLog("INFO");
        metricas.setFuncionalidade(funcionalidade);
        metricas.setDuracaoMs(duracaoProcesso);
        metricas.setDataHoraRequisicao(ManipulaData.milissegundosToStringDate(inicioProcesso));
        metricas.setDataHoraResposta(ManipulaData.milissegundosToStringDate(finalProcesso));
        metricas.setServidorOrigem(request.getRemoteAddr());
        metricas.setPortaOrigem(request.getRemotePort());
        metricas.setDominioAcesso(request.getLocalName());
        metricas.setPortaAcesso(request.getLocalPort());
        metricas.setUrlPath(request.getRequestURI());
        metricas.setMetodoHttp(request.getMethod());
        metricas.setIdTransacao(tracer.currentSpan().context().traceIdString());
        metricas.setIdSpan(tracer.currentSpan().context().spanIdString());
        metricas.setStatusHttp(response.getStatus());

        log.info(JSONConversor.toJSON(metricas));

        return result;

    }
}
,

我认为joinPoint.proceed();之后的代码不会在发生异常的情况下执行。 对于例外情况,您可以有不同的执行建议:

@AfterThrowing(pointcut = "springBeanPointcut()",throwing = "e")
  public void afterThrowingAdvice(JoinPoint jp,Exception e) {
   ....
  }
本文链接:https://www.f2er.com/3070308.html

大家都在问