关于session获取引发的问题,以及对其进行的思考

    最近玩了下使用的websocket技术做消息推送,过程中遇到了session的问题,问题描述如下:

用户登录的时,将用户信息保存到session中,用户主页通过ws协议的方式访问服务器,访问地址:ws://127.0.0.1:8080/webSocketServer",websocket拦截器获取用户seesion的时候,发现session为null。


    尝试调试过多次,session获取始终未空,问题出在哪呢?


我们来看一下session的概要:

Session概要

  Session 是用于保持状态的基于 Web 服务器的方法,在 Web 服务器上保持用户的状态信息供在任何时间从任何页访问。Session 允许通过将对象存储在 Web 服务器的内存中在整个用户会话过程中保持任何对象。当我们使用用户名和密码登陆网站,系统会首先验证当前登陆用户是否合法,当合法后将用户名等相关信息保存在Session 中。登陆后点击进入某功能页面时,系统也会去判断当前你是否有访问权限,判断的方式是验证Session 中的内容是否正确。

        Session是客户端与服务器端建立的会话,总是放在服务器上的,服务器会为每次会话建立一个sessionId,每个客户会跟一个sessionID对应。并不是关闭浏览器就结束了本次会话,通常是用户执行“退出”操作或者会话超时时才会结束。


session代表的是一个回话,在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。


服务器是如何实现一个session为一个用户浏览器服务的?

   服务器创建session出来后,会把session的id号,以cookie的形式回写给客户机,这样,只要客户机的浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现客户机浏览器带session id过来了,就会使用内存中与之对应的session为之服务。


来看一下session为null的实际案例:

服务端设置session的代码:

@RequestMapping("")
	public String index(HttpServletRequest httpRequest, String nickname) {
		HttpSession httpSession = httpRequest.getSession();
		System.out.println("###跳转进入到了首页###");
		User user = new User();

		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String dateString = formatter.format(new Date());

		user.setId(dateString + "-" + nickname);
		user.setNickname(nickname);

		// 登录操作
		// 判断是否是一个已经登录的用户,没有则登录
		if (null != httpSession.getAttribute("loginUser")) {
			// 清除旧的用户
			httpSession.removeAttribute("loginUser");
		}
		// 将用户放入session
		httpSession.setAttribute("loginUser", user);
		return "redirect:/index/mainpage";
	}

前端sebsocket获取session的代码:

var url = "ws://127.0.0.1:8080/"+ "webSocketServer";
ws = websocket.util.getWs(url);
websocket.util.onopen(ws);
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Map<String, Object> attributes) throws Exception {
		System.out.println("握手之前····");
		if (request instanceof ServletServerHttpRequest) {
			ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
			HttpSession session = servletRequest.getServletRequest().getSession(false);

			//如果用户已经登录,允许聊天
			if(session !=null && session.getAttribute("loginUser")!=null){
				//获取登录的用户
				User loginUser=(User)session.getAttribute("loginUser") ;
				//将用户放入socket处理器的会话(WebSocketSession)中
				attributes.put("loginUser", loginUser);
				System.out.println("Websocket:用户[ID:" + (loginUser.getId() + ",Name:"+loginUser.getNickname()+"]要建立连接"));
			}else{
				//用户没有登录,拒绝聊天
				//握手失败!
				System.out.println("--------------握手已失败...");
				return false;
			}
		}
		return super.beforeHandshake(request, response, wsHandler, attributes);
	}

通过beforeHandShake方法获取session为null,发现使用ip的方式,不是同一个sessionId,得到的session自然为null,改为如下方式进行请求就可以了:

<%
    String path = request.getContextPath();
    String basePath = request.getServerName() + ":" + request.getServerPort() + path + "/";
    String baseUrlPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
var url = "ws://" + path + "webSocketServer";
ws = websocket.util.getWs(url);
websocket.util.onopen(ws);

目前很多项目采用的是前后台分离的情况,关于前后端分离的session情况,笔人也测试过,目前前后台分离分2种情况部署:

一、在同一个服务器(tomcat)下部署,同源

    服务A:服务端代码:

@RequestMapping(value = "test", method = RequestMethod.GET)
	@ResponseBody
	public String test(HttpServletRequest request, HttpServletResponse httpResponse) {
		/*httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
		httpResponse.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8080");
		httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
*/
		//判断,如果没有session,则跳到登录页面
		HttpSession session = request.getSession();
		if(null != session.getAttribute("loginUser")){
			User user = (User) session.getAttribute("loginUser");
			System.out.println("session 不为空");
			return "session 不为空 nicknage :" + user.getNickname();
		}else{
			System.out.println("session ---------------------------- null");
			return "session ---------------------------- null";
		}
	}

    客户端A:前端代码:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>主界面</title>
    <script type="text/javascript" src="js/jquery-1.11.1.js"></script>
    <!-- js code -->
    <script type="text/javascript">
        function test() {
            var a_cross_domain_url = "http://10.162.11.18:8080/spring-websocket/index/test";
            alert(a_cross_domain_url);
            $.ajax({
                url: a_cross_domain_url,
                // 将XHR对象的withCredentials设为true
                xhrFields: {
                    withCredentials: false
                },
                success: function(data){
                    alert(data);
                    console.log(data);
                }
            });
        }

        function testAave() {
            var a_cross_domain_url = "http://10.162.11.18:8080/spring-websocket/index/saveSession";
            $.ajax({
                url: a_cross_domain_url,
                // 将XHR对象的withCredentials设为true
                xhrFields: {
                    withCredentials: false
                },
                success: function(data){
                    alert(data);
                    console.log(data);
                }
            });
        }
    </script>
</head>
<body>


<!-- 测试cession跨域问题 -->
<br /><br /><br />
<input type="button" onclick="test();" value="test crus" />

<br /><br /><br />
<input type="button" onclick="testAave();" value="save session" />
</body>
</html>

因为是同源的,所以不会存在跨域的问题,session也能正常的存和取!


二、在不同的服务器下部署,不同源

通过如上的方式访问肯定会遇到同源的问题,解决同源的问题可以看我这前写过的文章:ajax解决跨域问题,这样之后session也是能正常存和取的。

猜你喜欢

转载自blog.csdn.net/fengchao2016/article/details/80454821
今日推荐