获取IP地址信息时,一般我们需要一个HttpServletRequest对象,然后从请求头里获取x-forwarded-for
的值,而当我们使用dubbo+netty开发rest接口时,如果希望获取IP地址,HttpServletRequest是用不了的,你需要使用netty中的NettyRequestFacade对象,这时,你之前的获取IP地址的方法需要扩展,加一个只有入参不一样,代码逻辑完成一样的丑陋的,重复的代码;这无疑是一种代码的坏味道,应该想办法解决它。
适配器(包装器)
这种常用的设计模式在spring框架里用的非常多,如ServletRequestAttributes
,它包装了HttpServletRequest和HttpServletResponse,用来添加额外的功能,如获取请求参数、session等信息。
为获取IP地址添加包装
自己的http请求包装器接口RequestWrapper
public interface RequestWrapper { String getHeader(String name); String getRemoteAddr(); }
HttpServletRequest的包装
public class HttpRequestWrapper implements RequestWrapper { private final HttpServletRequest request; public HttpRequestWrapper(HttpServletRequest request) { this.request = request; } @Override public String getHeader(String name) { return request.getHeader(name); } @Override public String getRemoteAddr() { return request.getRemoteAddr(); } }
NettyRequestFacade的包装
public class NettyRequestWrapper implements RequestWrapper { private final NettyRequestFacade request; public NettyRequestWrapper(NettyRequestFacade request) { this.request = request; } @Override public String getHeader(String name) { return request.getHeader(name); } @Override public String getRemoteAddr() { return request.getRemoteAddr(); } }
获取IP地址方法,入参是一个http包装器
public static String getIpAddr(RequestWrapper request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); if (ip.equals("127.0.0.1")) { // 根据网卡取本机配置的IP InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ip = inet != null ? inet.getHostAddress() : ip; } } // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 if (ip != null && ip.length() > 15) { if (ip.indexOf(",") > 0) { ip = ip.substring(0, ip.indexOf(",")); } } if ("0:0:0:0:0:0:0:1".equals(ip)) { ip = "127.0.0.1"; } return ip; }
调用示例:
// 使用HttpServletRequest public String getIpFromHttp(HttpServletRequest request) { return getIpAddr(new HttpRequestWrapper(request)); } // 使用NettyRequestFacade public String getIpFromNetty(NettyRequestFacade request) { return getIpAddr(new NettyRequestWrapper(request)); }