Cookie机制
- cookie是浏览器用来存储少量数据的一种机制,数据以”key/value“形式存储,浏览器发送http请求时自动附带cookie信息
Session会话机制
- HTTP请求是无状态的,即HTTP协议并不能识别出上一个HTTP请求和下一个HTTP请求是否来自同一个用户
- 可以通过维持一个会话来判定用户:浏览器第一次请求服务器,服务器创建一个会话,并将会话的id作为响应的一部分发送给浏览器,浏览器存储会话id,并在后续第二次和第三次请求中带上会话id,服务器取得请求中的会话id就知道是不是同一个用户了
- 但是每次请求都携带会话id显然不靠谱,这时就可以通过cookie机制就实践会话id的传递
Tomcat下的Cookie和HttpServletSession
浏览器第一次访问Tomcat时,Tomcat会创建一个HttpServletSession会话对象,同时创建一个名为JSESSIONID的Cookie对象,该cookie存储着当前HttpServletSession会话对象的id,可以通过这个id找到当前会话,从而实现了用户状态的保持。而Session对象存活时间默认等于30分钟或者浏览器的打开时间,在这段时间内,我们可以获取Session对象中存储的任何信息。这就是Tomcat下Cookie和Session机制
更新项目操作Session对象
修改IndexController如下:
package com.zaomianbao.appdemo;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
@Controller
public class IndexController {
@RequestMapping("/")
public String index(HttpServletRequest request){
try {
System.out.println(new Date());
InetAddress addr = InetAddress.getLocalHost();
String ip=addr.getHostAddress().toString(); //获取本机ip
String host=addr.getHostName().toString(); //获取本机计算机名称
System.out.println(ip + " " + host);
request.setAttribute("ip",ip);
request.setAttribute("host",host);
HttpSession session = request.getSession();
String random = request.getParameter("random");
if(StringUtils.hasText(random)){
session.setAttribute("random",random);
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
return "index";
}
}
修改index.html如下
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>欢迎进入枣面包的面包坊</title>
<script type="text/javascript" src="js/nothing.js"></script>
</head>
<body>
<h1>欢迎进入枣面包的面包坊</h1>
<img src="img/photo.jpg"><br/>
主机名:<span th:text="${host}" ></span><br/>
ip:<span th:text="${ip}" ></span><br/>
session中的random值:<span th:text="${session.random}" ></span>
</body>
</html>
部署项目到Tomcat集群
[root@centos6-1 webapps]# rz
rz waiting to receive.
Starting zmodem transfer. Press Ctrl+C to cancel.
Transferring appdemo.war...
appdemo.war was skipped
[root@centos6-1 webapps]# scp -r appdemo.war root@centos6-2:$PWD
appdemo.war 100% 17MB 16.9MB/s 00:00
[root@centos6-1 webapps]# scp -r appdemo.war root@centos6-3:$PWD
appdemo.war 100% 17MB 16.9MB/s 00:00
[root@centos6-1 webapps]#
启动Tomcat集群
[root@centos6-1 bin]# ./startup.sh
[root@centos6-2 bin]# ./startup.sh
[root@centos6-3 bin]# ./startup.sh
浏览器访问Nginx
上一章讲到的Nginx集成Tomcat集群:大型网站分布式架构(八)—— Tomcat集群横向拓展 + Nginx负载均衡
1.直接访问Nginx:192.168.214.150/appdemo/
因为是初次访问,session中并未设置random值,所以取不到值
2.携带random参数访问:192.168.214.150/appdemo/?random=zaomianbao
发现random存入了session中,而此时处理这个请求的Tomcat是在centos6-1上的Tomcat1
3.连续直接访问Nginx:192.168.214.150/appdemo/
发现我们之前存入session中的random的值没有了,而博主并没有关闭浏览器,且是在连续请求的情况下,session也不可能过期。就连当请求分配给Tomcat1处理时也取不到random的值。
Session去哪了
其道理很简单:
- 当第一次打开浏览器请求并携带random参数时,请求分配给了Tomcat1,因为是第一次请求,这时Tomcat1响应回来时创建了名为JSESSIONID的cookie并携带回来给了浏览器
- 当浏览器连续第二次请求时,请求分给Tomcat2处理了,并且携带那个JSESSIONID的cookie给了Tomcat2,不管此时是否携带random参数,当在接口请求响应回来时,Tomcat2发现从名为JESESSIONID的cookie中获得的会话id并不能找到对应的HttpSession对象,所以Tomcat2重新创建了一个HttpSession,并将新的会话id放入名为JESESSION的cookie中返回给了浏览器
- 当浏览器连续第二次请求时,请求又分给Tomcat3处理了,又识别不了,又重新创建,又产生新的会话id返回给浏览器,不断重复此操作。
所以,问题在于Tomcat找不到Session对象,因为Session对象都存放在各自的Tomcat容器中,所以集群中的3台Tomcat容器找不到会话id对应的会话Session对象。所以得出结论:因为集群没有共享Session,所以导致会话的不断刷新,从而不能保持会话的状态。
总结
之前的Nginx+Tomcat集群的架构解决了高并发的问题,但又带来了Session会话状态的问题。下一章博主将通过使用Redis实现集群中的Session的共享