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
相关产品推荐
相关产品推荐

