获取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));
}