You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Quarkus Amazon Lambda HTTP扩展中装饰所有RESTEasy Reactive请求处理?

在AWS Lambda上的Quarkus RESTEasy Reactive应用中装饰所有HTTP请求(含异常场景)

由于RESTEasy Reactive的ContainerResponseFilter在资源抛出异常时不会执行,而Servlet过滤器在Lambda部署场景下不适用,推荐以下两种方案,其中Vert.x全局路由过滤器是最贴合需求的选择:

方案一:使用Vert.x全局路由过滤器(推荐)

Quarkus Amazon Lambda HTTP扩展底层基于Vert.x Web实现,通过@RouteFilter可以定义全局过滤器,覆盖所有请求的处理生命周期——包括请求开始、正常结束、异常终止的场景。

实现代码

import io.quarkus.vertx.web.RouteFilter;
import io.vertx.ext.web.RoutingContext;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class GlobalRequestTracker {

    // 优先级数值越小,过滤器执行越早
    @RouteFilter(100)
    public void trackRequest(RoutingContext ctx) {
        // 记录请求开始时间
        long startTime = System.currentTimeMillis();
        String requestPath = ctx.request().path();

        // 继续执行后续路由逻辑,注册完成回调(无论成功/失败都会触发)
        ctx.next(event -> {
            // 请求完成后的统一处理逻辑
            long duration = System.currentTimeMillis() - startTime;
            int statusCode = ctx.response().getStatusCode();

            // 示例:打印请求完成日志
            System.out.printf("请求 [%s] 处理完成,状态码: %d,耗时: %dms%n", requestPath, statusCode, duration);

            // 处理异常场景
            if (event.failed()) {
                Throwable exception = event.cause();
                System.err.printf("请求 [%s] 发生异常: %s%n", requestPath, exception.getMessage());
            }
        });
    }
}

优势

  • 覆盖所有进入应用的HTTP请求,包括RESTEasy路由、静态资源等
  • 不受RESTEasy异常处理流程影响,异常场景下仍能触发完成回调
  • 与Quarkus Lambda HTTP扩展的底层实现完全兼容

方案二:CDI拦截器(仅覆盖标注的REST资源)

如果只需要装饰REST资源方法的处理逻辑,可以使用CDI拦截器配合@AroundInvoke,通过try-finally块确保无论成功还是异常都能执行收尾逻辑。

步骤1:定义拦截器绑定注解

import jakarta.interceptor.InterceptorBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@InterceptorBinding
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TrackRequest {
}

步骤2:实现拦截器

import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;
import java.util.logging.Logger;

@Interceptor
@TrackRequest
public class RequestTrackingInterceptor {

    private static final Logger LOG = Logger.getLogger(RequestTrackingInterceptor.class.getName());

    @AroundInvoke
    public Object track(InvocationContext ctx) throws Exception {
        long startTime = System.currentTimeMillis();
        String resourceMethod = ctx.getMethod().getDeclaringClass().getSimpleName() + "." + ctx.getMethod().getName();
        
        try {
            // 执行目标资源方法
            return ctx.proceed();
        } catch (Exception e) {
            // 记录异常信息
            LOG.severe("资源方法 [" + resourceMethod + "] 处理异常: " + e.getMessage());
            throw e;
        } finally {
            // 无论成功/失败都执行的收尾逻辑
            long duration = System.currentTimeMillis() - startTime;
            LOG.info("资源方法 [" + resourceMethod + "] 处理完成,耗时: " + duration + "ms");
        }
    }
}

步骤3:在REST资源上标注

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@Path("/api")
@TrackRequest
public class ExampleResource {

    @GET
    @Path("/hello")
    public String hello() {
        return "Hello World";
    }
}

局限性

  • 仅能拦截标注了@TrackRequest的资源方法,无法覆盖所有HTTP请求
  • 对异步资源方法的拦截需要额外注意上下文传递

内容的提问来源于stack exchange,提问作者jdgilday

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 16:35:29