GlassFish 4.1中REST接口HttpServletRequest.getRemoteAddr()返回null求助
我之前在GlassFish 4.1上折腾REST应用时,也碰到过HttpServletRequest.getRemoteAddr()始终返回null的奇葩问题,结合自己的排查经验和踩过的坑,给你几个方向试试:
1. 先确认@Context注入的正确性
首先检查你的REST资源里,HttpServletRequest的注入方式是不是正确的。别小看这个,有时候不经意的错误注入会导致拿到的request实例不完整:
@Path("/test") public class TestResource { // 正确的注入方式:类级别的@Context注入 @Context private HttpServletRequest request; @GET @Produces(MediaType.TEXT_PLAIN) public String getRemoteAddress() { // 这里直接使用注入的request return "Remote Address: " + request.getRemoteAddr(); } }
如果是在方法参数里注入,也要确保参数位置正确,比如:
@GET public String getRemoteAddr(@Context HttpServletRequest request) { return request.getRemoteAddr(); }
避免在异步方法或者非请求线程里获取request,那样很容易拿到无效实例。
2. 检查GlassFish的HTTP监听器配置
GlassFish的监听器配置如果有问题,也会导致无法获取远程地址:
- 打开GlassFish管理控制台(默认地址
http://localhost:4848) - 进入
Configurations -> server-config -> Network Config -> Network Listeners - 选中你正在使用的监听器(比如
http-listener-1) - 检查Address字段是否设置为
0.0.0.0(允许所有IP访问),如果是127.0.0.1或者localhost,外部访问时可能会出现地址获取异常 - 另外确认Proxy Protocol选项没有被错误启用(你没有用代理,这个必须关闭)
3. 排查GlassFish版本的已知Bug
GlassFish 4.1本身存在不少遗留Bug,其中就包括JAX-RS环境下request远程地址无法正确传递的问题。最省心的解决办法是升级到Payara Server(它是GlassFish的官方衍生版,修复了大量原生GlassFish的bug),或者至少升级到GlassFish 4.1.1版本,很多用户反馈升级后这个问题就消失了。
4. 在过滤器里尝试替代方案
既然你试过过滤器但没用,可以试试在过滤器里打印更多request信息,看看是不是request被包装后丢失了地址:
public class RemoteAddrFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; // 先打印request的完整信息,看看里面有没有远程地址的痕迹 System.out.println("Request Details: " + request.toString()); // 尝试直接获取远程地址 String remoteAddr = request.getRemoteAddr(); System.out.println("Remote Addr: " + remoteAddr); // 即使没有代理,也可以试试这个兜底逻辑(万一有隐藏的本地转发) if (remoteAddr == null || remoteAddr.isEmpty()) { remoteAddr = request.getHeader("X-Forwarded-For"); if (remoteAddr == null) { remoteAddr = request.getRemoteHost(); } } System.out.println("Fallback Remote Addr: " + remoteAddr); chain.doFilter(req, res); } }
通过打印request的toString(),你可以看到这个request实例的实际类型和内部属性,有时候会发现是某个包装类没有正确实现getRemoteAddr()方法。
5. 检查是否使用嵌入式GlassFish
如果你的应用是运行在嵌入式GlassFish中,一定要确认启动时正确配置了HTTP连接器。比如在代码里启动嵌入式GlassFish时,要确保监听器绑定到正确的地址:
GlassFishProperties props = new GlassFishProperties(); props.setPort("http-listener-1", 8080); // 设置监听器允许所有IP访问 props.setProperty("network-config.network-listeners.network-listener.http-listener-1.address", "0.0.0.0"); GlassFish glassFish = GlassFishRuntime.bootstrap().newGlassFish(props); glassFish.start();
嵌入式GlassFish的默认配置有时候会限制地址获取,手动指定监听器地址能解决不少问题。
内容的提问来源于stack exchange,提问作者moretti.fabio

