获取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;}@Overridepublic String getHeader(String name) {return request.getHeader(name);}@Overridepublic String getRemoteAddr() {return request.getRemoteAddr();}}
NettyRequestFacade的包装
public class NettyRequestWrapper implements RequestWrapper {private final NettyRequestFacade request;public NettyRequestWrapper(NettyRequestFacade request) {this.request = request;}@Overridepublic String getHeader(String name) {return request.getHeader(name);}@Overridepublic 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")) {// 根据网卡取本机配置的IPInetAddress 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));
}