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

Quarkus(Jakarta EE)拦截器中如何获取客户端IP地址?

问题描述

我正在开发基于Jakarta EE的Quarkus Web应用,应用里包含多个@GET和@POST方法,想记录这些方法的调用情况,写了如下拦截器代码:

@Loggable
@Interceptor
@Priority(1)
public class Logger {
    
    @Inject
    private LogService logService;
    
    @AroundInvoke
    public Object logMethodEntry(InvocationContext context) throws Exception {
        Date currentDateAndTime = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        String dateAndTime = dateFormat.format(currentDateAndTime);
        String methodName = context.getTarget().getClass().getName() + "." + context.getMethod().getName();
        String ipAddress = "";


        Log log = new Log(dateAndTime, ipAddress, methodName);
        logService.addLog(log);
        return context.proceed();
    }
}

这个拦截器通过@Loggable注解注册到目标类,现在的问题是如何获取客户端IP地址?尝试使用HttpServletRequest时出现依赖编译错误。注:该拦截器仅用于@GET和@POST方法,始终存在HTTP请求。


解决方案

在Quarkus中,可通过以下几种方式在拦截器里获取客户端IP,同时避免编译错误:

方法1:使用@Context注入请求对象

传统Resteasy场景

确保项目依赖包含quarkus-resteasy,直接通过jakarta.ws.rs.core.Context注入HttpServletRequest:

@Loggable
@Interceptor
@Priority(1)
public class Logger {
    
    @Inject
    private LogService logService;
    
    @Context
    private HttpServletRequest request;
    
    @AroundInvoke
    public Object logMethodEntry(InvocationContext context) throws Exception {
        Date currentDateAndTime = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        String dateAndTime = dateFormat.format(currentDateAndTime);
        String methodName = context.getTarget().getClass().getName() + "." + context.getMethod().getName();
        
        // 获取基础客户端IP
        String ipAddress = request.getRemoteAddr();
        // 处理反向代理(如Nginx)后的真实IP
        String forwardedFor = request.getHeader("X-Forwarded-For");
        if (forwardedFor != null && !forwardedFor.isEmpty()) {
            ipAddress = forwardedFor.split(",")[0].trim();
        }

        Log log = new Log(dateAndTime, ipAddress, methodName);
        logService.addLog(log);
        return context.proceed();
    }
}

Reactive Resteasy场景

如果使用quarkus-resteasy-reactive,则注入io.vertx.ext.web.RoutingContext:

@Loggable
@Interceptor
@Priority(1)
public class Logger {
    
    @Inject
    private LogService logService;
    
    @Context
    private RoutingContext routingContext;
    
    @AroundInvoke
    public Object logMethodEntry(InvocationContext context) throws Exception {
        // ... 其他代码
        
        String ipAddress = routingContext.request().remoteAddress().hostAddress();
        // 处理反向代理场景
        String forwardedFor = routingContext.request().getHeader("X-Forwarded-For");
        if (forwardedFor != null && !forwardedFor.isEmpty()) {
            ipAddress = forwardedFor.split(",")[0].trim();
        }

        // ... 后续代码
    }
}

方法2:从InvocationContext参数中提取请求对象

如果不想直接注入,可遍历拦截方法的参数,查找HttpServletRequest实例:

@AroundInvoke
public Object logMethodEntry(InvocationContext context) throws Exception {
    // ... 其他代码
    
    String ipAddress = "";
    // 遍历方法参数获取请求对象
    for (Object param : context.getParameters()) {
        if (param instanceof HttpServletRequest req) {
            ipAddress = req.getRemoteAddr();
            String forwardedFor = req.getHeader("X-Forwarded-For");
            if (forwardedFor != null && !forwardedFor.isEmpty()) {
                ipAddress = forwardedFor.split(",")[0].trim();
            }
            break;
        }
    }

    // ... 后续代码
}

依赖检查

若之前出现编译错误,确认项目依赖中包含对应扩展:

  • 传统Resteasy(Maven):
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy</artifactId>
</dependency>
  • Reactive Resteasy(Maven):
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 10:56:03