spring websocket握手时无法获取httpSession中的值

雾里看花の java工程师  2018-08-01 09:21:05
最近在用spring websocket的时,发现在握手的时候无法通过httpSession.getAttribute()获取用户信息,找了下网上的资料,有说登录的ip要和websocket连接的ip统一的,有说要价格listener监听器,让所有request都加上httpSession的,这些我都试了下,还是无法获取,请问你们知道怎么解决吗?(spring是4.3.13版本),下面是相关配置:
首先,spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket-4.3.xsd">

<!-- 自动扫描,使SpringMVC认为包下用了@Controller注解的类是控制器 -->
<context:component-scan base-package="com.test.websocket.controller" />
<!-- 扩充了注解驱动,可以将请求参数绑定到控制器参数 -->
<mvc:annotation-driven />
<!-- 静态资源处理 css js imgs -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:resources mapping="/**/*.html" location="/" />
<mvc:resources mapping="/**/*.js" location="/"/>
<mvc:resources mapping="/**/*.css" location="/"/>
<!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760000"></property>
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960"></property>
<!-- 启用是为了推迟文件解析,以便捕获文件大小异常 -->
<property name="resolveLazily" value="true"></property>
</bean>

<!-- 对模型视图名称的解析,在请求时模型视图名称添加前后缀 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
</bean>

<!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>

<!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<!-- JSON转换器 -->
<ref bean="mappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>

<!-- websocket处理类 -->
<bean id="springWebSocketHandler" class="com.test.websocket.push.SpringWebSocketHandler"/>

<!-- 握手接口/拦截器 -->
<bean id="springWebSocketHandlerInterceptor" class="com.test.websocket.push.SpringWebSocketHandlerInterceptor"/>

<websocket:handlers >
<websocket:mapping path="/socketServer.do" handler="springWebSocketHandler"/>
<websocket:handshake-interceptors>
<ref bean="springWebSocketHandlerInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>

<!-- 注册 sockJS -->
<websocket:handlers>
<websocket:mapping path="/sockjs/socketServer.do" handler="springWebSocketHandler"/>
<websocket:handshake-interceptors>
<ref bean="springWebSocketHandlerInterceptor"/>
</websocket:handshake-interceptors>
<websocket:sockjs />
</websocket:handlers>

</beans>

SpringWebSocketHandler

package com.test.websocket.push;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.test.websocket.base.SessionKey;

@Component("springWebSocketHandler")
public class SpringWebSocketHandler extends TextWebSocketHandler{

private static final Logger logger = LoggerFactory.getLogger(SpringWebSocketHandler.class);

private static Map<String, WebSocketSession> users = new HashMap<String, WebSocketSession>();

/**
* 连接成功时候,会触发页面上onopen方法
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String userid = (String) session.getAttributes().get(SessionKey.USERID);
users.put(userid, session);
logger.info("用户:" + userid + "连接了...");
logger.info("connect to the websocket success......当前在线数量:"+users.size());
TextMessage returnMessage = new TextMessage("连接成功!");
session.sendMessage(returnMessage);
}

/**
* 关闭连接时触发
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
String userid = (String) session.getAttributes().get(SessionKey.USERID);
users.remove(userid);
logger.info(userid + "is closed......剩余在线数量:"+users.size());
}

/**
* js调用websocket.send时候,会调用该方法
*/
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
super.handleTextMessage(session, message);
}

/**
* 传输消息出错时触发的回调
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if(session.isOpen()){
session.close();
}
String userid = (String) session.getAttributes().get(SessionKey.USERID);
users.remove(userid);
logger.info(userid + "is closed......剩余在线数量:"+users.size());
}

/**
* 给某个用户发消息
* @param userid
* @param textMessage
* @throws IOException
*/
public void sendMessageToUser(String userid, TextMessage textMessage) throws IOException {
WebSocketSession session = users.get(userid);
if(session != null && session.isOpen()) {
session.sendMessage(textMessage);
}
}
/**
* 给所有用户发消息
* @param textMessage
* @throws IOException
*/
public void sendMessageToAll(TextMessage textMessage) throws IOException {
WebSocketSession session = null;
for(Map.Entry<String, WebSocketSession> entry : users.entrySet()) {
session = entry.getValue();
if(session != null && session.isOpen()) {
session.sendMessage(textMessage);
}
}
}

}



SpringWebSocketHandlerInterceptor

package com.test.websocket.push;

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import com.test.websocket.base.SessionKey;
import com.test.websocket.entity.User;

public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor{

@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession();
if (session != null) {
User user = (User) session.getAttribute(SessionKey.USERINFO);
if(user != null) {
attributes.put(SessionKey.USERID, user.getUserId());
}
}
}
return super.beforeHandshake(request, response, wsHandler, attributes);
}

@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {

super.afterHandshake(request, response, wsHandler, ex);
}

}



send.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>websocket消息</title>
</head>
<body>

请输入:<textarea rows="5" cols="10" id="inputMsg" name="inputMsg"></textarea>
<button onclick="doSend();">发送</button>

<script type="text/javascript" src="/websocket/resources/js/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="/websocket/resources/sockjs-client-1.1.5/sockjs.min.js"></script>
<script type="text/javascript">
var websocket = null;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://"+window.location.host+"/websocket/socketServer.do");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://"+window.location.host+"/websocket/socketServer.do");
} else {
websocket = new SockJS("http://"+window.location.host+"/websocket/sockjs/socketServer.do");
}
websocket.onopen = onOpen;
websocket.onmessage = onMessage;
websocket.onerror = onError;
websocket.onclose = onClose;

//当网络连接建立时触发该事件
function onOpen(openEvt) {
//alert(openEvt.Data);
}

//当websocket接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件
function onMessage(evt) {
console.log(evt.data);
}

...全文
175 点赞 收藏 3
写回复
3 条回复
雾里看花の 2018年08月03日
发现了一个问题,用谷歌浏览器时,后台是可以正常通过httpSession获取值的,但是用360极速浏览器的话,就不知道为什么,虽然可以连接成功,但是无法通过httpSession获取值,是我客户端代码写错了?下面是我的客户端代码

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>websocket消息</title>
</head>
<body>

请输入:<textarea rows="5" cols="10" id="inputMsg" name="inputMsg"></textarea>
<button onclick="doSend();">发送</button>

<script type="text/javascript" src="/ssm/resources/js/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="/ssm/resources/sockjs-client-1.1.5/sockjs.min.js"></script>
<script type="text/javascript">
var websocket = null;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://"+window.location.host+"/ssm/socketServer.do");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://"+window.location.host+"/ssm/socketServer.do");
} else {
websocket = new SockJS("http://"+window.location.host+"/ssm/sockjs/socketServer.do");
}
websocket.onopen = onOpen;
websocket.onmessage = onMessage;
websocket.onerror = onError;
websocket.onclose = onClose;

//当网络连接建立时触发该事件
function onOpen(openEvt) {
//alert(openEvt.Data);
}

//当websocket接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件
function onMessage(evt) {
console.log(evt.data);
}

//当网络发生错误时触发该事件
function onError() {}

//当websocket被关闭时触发该事件
function onClose() {}

//向服务器发送数据
function doSend() {
if (websocket.readyState == websocket.OPEN) {
var msg = document.getElementById("inputMsg").value;
websocket.send(msg);//调用后台handleTextMessage方法
alert("发送成功!");
} else {
alert("连接失败!");
}
}
   window.close=function(){
     websocket.onclose();
   }
</script>
</body>
</html>
回复 点赞
雾里看花の 2018年08月03日
引用 2 楼 cnm_xinlei 的回复:
楼主,我上次遇到和你一样的问题,也是在谷歌浏览器上可以,但在360浏览器上就死活无法获取httpSession里的值,当时我用的是360浏览器的隐身模式,后来我浏览模式改成正常模式,连接websocket后是可以通过httpSession获取值的,总而言之,就是360浏览器隐身模式搞的鬼。后来我又去试了下谷歌浏览器的隐身模式,它是正常的,隐身模式也可以获取httpSession中的值。目前暂时不知道怎么解决360浏览器这个问题。。。

被你这么一说还真是,我就是用的360极速浏览器的隐身模式连接的websocket,灰常感谢啊。。。这都可以被你发现,大神啊。。。
回复 点赞
cnm_xinlei 2018年08月03日
楼主,我上次遇到和你一样的问题,也是在谷歌浏览器上可以,但在360浏览器上就死活无法获取httpSession里的值,当时我用的是360浏览器的隐身模式,后来我浏览模式改成正常模式,连接websocket后是可以通过httpSession获取值的,总而言之,就是360浏览器隐身模式搞的鬼。后来我又去试了下谷歌浏览器的隐身模式,它是正常的,隐身模式也可以获取httpSession中的值。目前暂时不知道怎么解决360浏览器这个问题。。。
回复 点赞
发动态
发帖子
Web 开发
创建于2007-09-28

5.2w+

社区成员

34.1w+

社区内容

Java Web 开发
社区公告
暂无公告