Nginx反向代理websocket协议的情况使用springboot项目获取客户端ip的地址
- 本文只演示springboot项目的配置,其他项目请根据本文的配置自行配置
- nginx的相关配置
- springboot的配置
- 解决办法
本文只演示springboot项目的配置,其他项目请根据本文的配置自行配置
因为目前项目只是在用springboot,所以只演示springboot的相关配置,如果有其他类型的项目,请自行根据本文配置自行配置。
nginx的相关配置
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server{
location / {
proxy_pass 代理的ip+端口+项目;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
springboot的配置
因为项目最开始的时候是没有通过nginx的代理的,所以是通过websocket连接时的session获取的ip地址,代码如下:
//此处是websocket的方法
public Session session;
private String ipaddr;
private Integer userId;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
ipaddr = WebSocketUtil.getRemoteAddress(session).getAddress().toString().substring(1);
System.out.println(ipaddr);
// ipaddr = (String) session.getUserProperties().get("ClientIP");//将客户端IP地址从WebSocket的session中取出
// System.out.println(ipaddr);
// webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
try {
sendMessage("连接成功");
} catch (IOException e) {
System.out.println("IO异常");
}
}
//此处是工具类
public class WebSocketUtil {
public static InetSocketAddress getRemoteAddress(Session session) {
if (session == null) {
return null;
}
Async async = session.getAsyncRemote();
//在Tomcat 8.0.x版本有效
// InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async,"base#sos#socketWrapper#socket#sc#remoteAddress");
//在Tomcat 8.5以上版本有效
InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async, "base#socketWrapper#socket#sc#remoteAddress");
return addr;
}
private static Object getFieldInstance(Object obj, String fieldPath) {
String fields[] = fieldPath.split("#");
for (String field : fields) {
obj = getField(obj, obj.getClass(), field);
if (obj == null) {
return null;
}
}
return obj;
}
private static Object getField(Object obj, Class<?> clazz, String fieldName) {
for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
try {
Field field;
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
}
}
return null;
}
}
后面添加了nginx代理后,此方法获取的全都是代理服务器的ip地址,网上查询相关资料后,说的是可以通过springboot配置tomcat的相关配置文件,就可以获取到客户端的真实ip,但是通过配置之后用上边的方法还是获取不到客户端的ip,一直是代理服务器的ip,但是通过配置完成之后发现request却可以获得客户端的真实ip,那我们不得不换个想法,是否可以获取到request从而来获取ip呢?
解决办法
springboot配置tomcat的内容,我使用的是.properties文件,yml文件的话根据以下文件自行配置:
server.tomcat.protocol-header=X-Forwarded-Proto
server.tomcat.remote-ip-header=X-Forwarded-For
server.tomcat.protocol-header-https-value=http
server.tomcat.port-header=X-Forwarded-Port
当nginx和spingboot的配置完成之后,我们就来获取request。
首先是创建一个类来继承Configurator:
public class HttpSeesionConfigurator extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
sec.getUserProperties().put(HandshakeRequest.class.getName(),request);
}
}
然后在@ServerEndpoint注解里面添加configurator属性
@ServerEndpoint(value = "/websocket",configurator = HttpSeesionConfigurator.class)
在onOpen方法里加入参数EndpointConfig config即可获取request
@OnOpen
public void onOpen(Session session,EndpointConfig config) {
// HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
HandshakeRequest request = (HandshakeRequest)config.getUserProperties().get(HandshakeRequest.class.getName());
List<String> strings = request.getHeaders().get("x-real-ip");
String s = strings.get(0);
this.session = session;
if (StringUtils.isBlank(s)){
ipaddr = WebSocketUtil.getRemoteAddress(session).getAddress().toString().substring(1);
}
ipaddr =s;
System.out.println(ipaddr);
// ipaddr = (String) session.getUserProperties().get("ClientIP");//将客户端IP地址从WebSocket的session中取出
// System.out.println(ipaddr);
// webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
try {
sendMessage("连接成功");
} catch (IOException e) {
System.out.println("IO异常");
}
}
然后通过获取到的request获取到用户的的真实ip。
其实这只算是一个取巧的方法,如果有人在用springboot配置好tomcat的情况下直接通过最开始的session获取到真实的ip是更好地,但是我没有做到,如果有人成功了,还望告知,谢谢~