一、概述
会话技术:就是一次谈话,在Web浏览器跟服务器的一次通信,那这次通信可以包含多次请求和多次响应
功能:在多次请求和多次响应间共享数据,记录信息确定用户身份
会话的结束标志:浏览器关闭,或者服务器关闭了代表这次会话就结束
分类:
(1)客户端会话技术:数据由客户端来保存
(2)服务端会话技术:数据由服务端来保存
二、客户端的会话技术--Cookie
(1)Cookie的由来(诞生)
HTTP的特点:Web应用程序是使用HTTP协议传输数据的,而HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接,这就意味着服务器无法从连接上跟踪会话。
需求引出:用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了,要跟踪该会话,必须引入一种机制。
即:一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如:用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。
说明:Cookie就是这样的一种机制,它就是为了弥补HTTP协议无状态的不足。
补充:在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话
应用场景:我们在浏览器中,经常涉及到数据的交换,比如你登录邮箱,登录账号等,会设置30天内记住我或者自动登录。
思考:那么它们是怎么记录信息的呢?
提前解答:答案就是今天的主角Cookie了,Cookie是由HTTP服务器设置的,保存在浏览器中,但HTTP协议是一种无状态协议,在数据交换完毕后,服务器端和客户端的链接就会关闭,每次交换数据都需要建立新的链接。就像我们去超市买东西,没有积分卡的情况下,我们买完东西之后,超市没有我们的任何消费信息,但我们办了积分卡之后,超市就有了我们的消费信息。cookie就像是积分卡,可以保存积分,商品就是我们的信息,超市的系统就像服务器后台,http协议就是交易的过程。
(2)什么是Cookie?
Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。
(3)Cookie的原理图
说明:由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份,怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证,这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。①客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie(setCookie),客户端浏览器会把Cookie保存起来。②当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态,服务器还可以根据需要修改Cookie的内容。
原理:
1.客户端请求一个资源,服务器做出响应时,会发送set-cookie头
2.客户端接收到响应,会将数据保存在客户端浏览器中
3.客户端再一次请求服务器时,会通过cookie头携带该数据。
4.服务端接收到请求,会来解析获取数据
(4)Cookie的分类
cookie分为会话cookie和持久cookie
① 会话cookie:不设定它的生命周期,仅存活于当前的会话中(浏览器的缓存中);前面说了浏览器的开启到关闭就是一次会话,当关闭浏览器时,会话cookie就会跟随浏览器而销毁(HTTP的无状态所致)。当关闭一个页面时,不影响会话cookie的销毁。会话cookie就像我们没有办理积分卡时,单一的买卖过程,离开之后,信息则销毁。
②持久cookie:设定了它的生命周期,持久化(序列化)到硬盘中。此时cookie像商品一样,有个保质期,关闭浏览器之后,它不会销毁,直到设定的过期时间。对于持久cookie,可以在同一个浏览器中传递数据,比如你在打开一个淘宝页面登陆后,你在点开一个商品页面,依然是登录状态,即便你关闭了浏览器,再次开启浏览器,依然会是登录状态。这就是因为cookie自动将数据传送到服务器端,再反馈回来的结果。持久cookie就像是我们办理了一张积分卡,即便离开,信息一直保留,直到时间到期,信息销毁。
体验:同一个浏览器中登陆某一个app后,不需要再登陆。
补充:不同的浏览器采用不同的方式保存Cookie
(5)有关Cookie的几个方法
setMaxAge(int second)
说明:正数:持久化到硬盘上;负数:默认值-1存在浏览器内存(缓存)中;0:删除cookie。
(6)测试
Servlet01--设置cookies的数据
package org.wzj.com;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
@WebServlet(name = "Servlet01",value = "/test01")
public class Servlet01 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("设置Cookie数据!");
//(1)设置Cookie---注意:Cookie的对象不是服务器创建的,需要开发者自己手动创建---键值对的形式
//注意:Cookie是不支持中文字符的
Cookie cookie1 = new Cookie("username", "Jane");
Cookie cookie2 = new Cookie("id", URLEncoder.encode("国产零零七", "utf-8"));
//(2)设置cookie的存活时间(会话结束后),
cookie1.setMaxAge(80);
cookie2.setMaxAge(80);
//(3)服务器请求的时候,服务器做出响应(发送到浏览器端)--发送Cookie数据,注意抓包查看
response.addCookie(cookie1);
response.addCookie(cookie2);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
Servlet02--获取cookies的数据
package org.wzj.com;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "Servlet02",value = "/test02")
public class Servlet02 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//(1)从当前的会话中取出所有保存的cookie数据,打印到控制台(后台)
Cookie[] cookies = request.getCookies();
//(2)取出数据打印到控制台
if(cookies!=null){
for(Cookie cookie:cookies){
//如何判断是不是我刚才存储的cookie数据
String s = cookie.getName();//获取cookie的键
if(s.equals("username")){
String value = cookie.getValue();//根据键找值
System.out.println(value);
}
if(s.equals("id")){
String value = cookie.getValue();
System.out.println(value);
}
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
(7)Cookie需要注意的几个问题
①Cookie持久化的问题
默认浏览器会将Cookie的数据包浏览器的内存当中,浏览器一关闭内存一释放,保存的数据就没了,那么我们肯定想要这个Cookie数据保存到硬盘上,浏览器即便关了在存活期,下次请求还是能够带回来的,服务器可以设置Cookie保存的位置以及周期。
②Cookie的键和值都是字符串类型
③Cookie 不支持中文的解决办法
(8) Cookie的修改、删除
(9) Cookie的域
补充:Cookie机制定义了两种报头Set-Cookie报头和Cookie报头,set-cookie存在于服务器响应的消息头中,而cookie则存在于客户端请求的消息头中
三、服务器端会话技术--Session
(1) 将数据存储在服务器端
(2) session实现原理
原理:用户请求时,服务器先创建session出来后,会把session的id号,以cookie的形式回响应给客户端;这样只要客户机的浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现客户机浏览器带session的id过来了,就会使用服务器内存中与之对应的session为之服务。
具体:在打开浏览器第一次请求该jsp的时候,服务器会自动(理解--服务器对应的代码)为其创建一个session,并赋予其一个sessionID,发送给客户端的浏览器。以后客户端接着请求本应用中其它资源的时候,会自动在请求头上添加:Cookie:JSESSIONID=客户端第一次拿到的session ID,这样服务器端在接到请求时候,就会收到session ID,并根据ID在浏览器的内存中找到之前创建的session对象,提供给请求使用,这也是session使用的基本原理,必须搞懂这个。
关键:session依赖于cookie存在;
(3)原理图
解释: 假如浏览器A先访问Servlet1,这时候它创建了一个Session,Jsessionid号为110,然后Servlet1(服务器)将这个Jsessionid号以Cookie的方式返回给浏览器A,接着如果浏览器A继续访问Servlet2,那么这个请求会带上Cookie值: JSESSIONID=110,然后服务器根据浏览器A(携带)传递过来的ID号找到内存中的这个Session。 这时候假如浏览器B来访问Servlet1了,它的请求并没有带上JSESSIONID这个Cookie值,由于它也要使用Session,所以服务器会新创建一个Session,JSESSIONID号为119,并将这个ID号以Cookie的方式返回给浏览器B,之后的过程就同A了。
补充:用户第一次请求,服务器调用 request.getSession()方法时,服务器会检查是否已经有对应的session,如果没有就在内存中创建一个session并返回给客户端该session的一个id以cookie保存,有的话就会在。
注:其中Servlet1用于创建Session并添加属性;Servlet2用于读取Session中的属性。
说明:Session只针对当前的浏览器。
第一次请求的时候,服务器给予的响应信息(Set-Cookie)
第二次请求本应用中其他资源的时候,会自动在请求头上添加Cookie:如下所示
(4)Session的细节
思考①:浏览器关闭了,再次请求session一样吗?
答:不一样了
原因:浏览器关闭了(相当于会话结束),默认session仅存活于当前的会话中(如果没有将session持久化,保存的jsessionid没了),相当于创建了一个新的session
思考②:服务器关闭了,再次请求session一样吗?
答:也不一样,会话结束,内存(缓存)释放了,但是虽然对象不一样了,但是session中存储的数据还是一样的(如何测试?)
5AA2703214C2400A3108A263817B2E6C:hehe
5AA2703214C2400A3108A263817B2F7G:hehe
他是如何识别是同一用户:是IP+端口+浏览器吗?
引出:钝化和活化
钝化:服务器正常关闭后,session对象会被写入(序列化)硬盘的文件中(测试时找其存储的位置)
活化:服务器开启后,将文件还原(反序列化)为内存中的session对象(对应的文件消失)
注意:session包含的内容是实现java.io.Serializable接口的类的实例,否则无法钝化和活化!!!
场景解析:
淘宝每年都会有定时抢购的活动,很多用户会提前登录等待,长时间不进行操作,一直保存在内存中,而到达指定时刻,几十万用户并发访问,就可能会有几十万个session, 服务器被很多的session访问,内存不足,为了更好的运行,这时就需要进行对象的活化、钝化。即:将一部分比较长时间没有变动的session从内存中写入到硬盘,让其在闲置的时候离开内存,将session信息保存至硬盘,等该session的用户重新使用的时候,那么该session文件就会自动从硬盘上加载到内存中,相当于会话没有中断,用户在整个过程中发觉不出来session又被调动的影响。
性能优化方案:用户信息不会丢失,并且最大限度的提高服务器(内存)的利用率。
场景2:服务器维护需要
(5) session的生命周期
①创建:
request.getSession():
//会根据jsessionid值查找是否存在sesison对象,如果没找到则创建新的session
② 销毁:
1)Session超时
超时:指的是连续一定时间服务器没有收到该Session所对应客户端的请求并且超过了服务器设置的Session超时的最大时间。
如何设置Session的有效时间(默认是30分钟),在server.xml中配置
<session-config>
<session-timeout>30</session-timeout>
</session-config>
2)程序调用session.invalidate();----让session自杀!
3)服务器关闭或服务停止
思考③:如果客户端禁用了 cookie,session该如何自处?
说明:客户端禁用了cookie,session将不一样。
重写URL,将;jsessionid=731DED0DC4F0AA06CDBB815733D4043E拼接在地址栏中
形如:http://localhost:8080/day09/s1;jsessionid=731DED0DC4F0AA06CDBB815733D4043E
说明:最好用Eclipse测试,IDEA中重启服务器会重新打开一个页面,所以看不到实验效果。
代码:
PrintWriter pw = response.getWriter();
HttpSession session = request.getSession();
String id = session.getId();
String href = "/day09/s1";
href = response.encodeRedirectURL(href);
System.out.println(href);
pw.write("<a href='"+href+"'>s1</a>");
4.获取session:
getSession(boolean flag)true:默认值,会根据jsessionid值查找是否存在sesison对象,如果没找到,则创建新的session
false:会根据jsessionid值查找是否存在sesison对象,如果没找到,则返回null
四、对比
客户端会话技术: Cookie 将数据保存客户端 服务器压力小,数据不安全。
服务端会话技术: 将数据保存在服务端,服务器压力大,数据安全。
相关链接:
分布式session:点击打开链接
session原理及实现集群session的方案原理:点击打开链接
Session之实现原理的深入讨论(禁用Cookie):点击打开链接
session:点击打开链接
大神:点击打开链接
应用场景(其中):点击打开链接
Cookie的原理:点击打开链接,点击打开链接,点击打开链接
会话跟踪技术:点击打开链接(URL),点击打开链接(SSL)