10.1 什么是会话
会话:
- 从<mark>浏览器打开</mark>,访问服务器开始,一直到访问服务器结束,<mark>浏览器关闭为止</mark>,
- <mark>这期间</mark>浏览器和服务器之间产生的<mark>多次请求和响应</mark>加在一起,就称之为浏览器和服务器之间的<mark>一次会话</mark>。
在一次会话中,往往会产生一些数据,而这些数据又需要我们保存起来,如何保存会话中产生的数据?
(保存到数据库⇒ jdbc,这里不讨论)
- <mark>cookie</mark>
- session
10.2 Cookie
- 《深入理解Cookie》 - https://www.jianshu.com/p/6fc9cea6daa2
10.2.1 Cookie的工作原理
Cookie是将会话中产生的数据保存在<mark>客户端</mark>浏览器内部。
Cookie是<mark>客户端技术</mark>。
Cookie是基于两个头进行工作的,分别是
Set-Cookie
<mark>响应头</mark>和Cookie
<mark>请求头</mark>。
通过 Set-Cookie响应头
负责将Cookie信息发送给浏览器,让浏览器以Cookie的形式保存在内部(保存cookie)
浏览器内部一旦保存了Cookie
,以后<mark>每次访问服务器都会通过一个Cookie请求头,将cookie再带给服务器</mark>(除非cookie过期)
HTTP协议本身是无状态的。
什么是无状态呢,即服务器无法判断用户身份。
<mark>Cookie实际上是一小段的文本信息(key-value格式)</mark>。
客户端向服务器发起请求,如果<mark>服务器需要记录该用户状态</mark>,就使用response向<mark>客户端浏览器颁发一个Cookie</mark>。
<mark>客户端浏览器会把Cookie保存起来</mark>。
当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。
<mark>服务器检查该Cookie,以此来辨认用户状态</mark>。
<mark>打个比方,我们去银行办理储蓄业务,第一次给你办了张银行卡,里面存放了身份证、密码、手机等个人信息。当你下次再来这个银行时,银行机器能识别你的卡,从而能够直接办理业务</mark>。
∗∗注意: request、response均包含Cookies
但他们内容不一样。
- request 中包含的是<mark>客户端</mark>发过来的 “<mark>旧Cookies</mark>”
- response 中包含的是<mark>服务器</mark>发回给<mark>客户端</mark>的 “<mark>新Cookies</mark>”
10.2.2 Cookie的API及应用
1、创建Cookie对象
Cookie cookie = new Cookie(String name, String value);
-- 创建一个Cookie对象, 同时指定Cookie的名字和cookie中保存的值
2、将Cookie添加到response响应中
response.addCookie(Cookie c) ;
-- 通过response提供的addCookie方法,将cookie对象保存到响应中。再发送给浏览器保存
-- 底层通过 Set-Cookie 响应头将 cookie 带给浏览器保存的。
-- 可以多次调用该方法,即可以添加一个以上的cookie到响应中。
3、获取请求中的所有cookie对象组成的数组
Cookie[] cs = request.getCookies();
-- 从请求中获取所有cookie对象组成的数组,如果请求中没有任何cookie,该方法将会返回null值。(不是空的数组)
4、删除Cookie
<mark>没有提供直接删除Cookie的方法</mark>。
<mark>可以向浏览器再发送一个同名的Cookie,设置Cookie的最大存活时间为零</mark>。
由于浏览器是根据Cookie的名字区分一个Cookie,因此两次发送相同名字的Cookie,浏览器会认为是同一个,后发送的Cookie将会覆盖之前发送的Cookie。
而后发的Cookie,由于设置了生存时间为零,所以浏览器收到后也会立即删除!
代码示例:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//1.创建一个同名的Cookie,并设置生存时间为零
Cookie c = new Cookie("prod", "");
c.setMaxAge( 0 );
//2.将cookie添加到响应中,发送给浏览器
response.addCookie( c );
//3.做出响应。
out.write("成功删除了名称为prod的cookie!");
}
5、Cookie的常用方法
cookie.getName() -- 获取 cookie 的名字 【名字没法改】
cookie.getValue() -- 获取 cookie 中保存的值(数据)
cookie.setValue() -- 设置 cookie 中保存的值(数据)
cookie.setMaxAge() -- 下面。。
6、setMaxAge方法 – 设置 cookie 的最大生命时间
默认也有个时间,但是时间不确定。
跟会话有关,会话结束,cookie死亡。
– 设置cookie的最大存活时间。
– 如果不设置该方法,cookie默认是保存在浏览器的内存中,在浏览器关闭时,随着内存的释放,cookie也会销毁。同时,浏览器关闭,会话也结束了。因此默认cookie的存活时间是一次会话。
– 如果要保证浏览器关闭后再打开Cookie仍然存在,可以为cookie设置一个最大生存时间。通过SetMaxAge方法可以设置cookie最大存活时间,设置后,cookie将不会保存在浏览器内存里,而是以文件形式保存在浏览器的临时目录下(硬盘上)
例如:
//2.创建一个cookie,将商品信息保存到cookie中
Cookie cookie = new Cookie( "prod", prod );
//设置cookie最大生存时间, 单位是秒
cookie.setMaxAge( 3600 * 24 * 30 );
//3.将cookie添加到响应中.
response.addCookie( cookie );
10.2.3 Cookie中保存中文数据的问题
HTTP协议中规定了请求信息和响应信息中不能包含中文数据!!
因此通过浏览器向服务器发送中文数据时,浏览器会将中文数据进行URL编码,编码为下面这种格式:
http://localhost/day13-cookie/index.html?user=%E5%BC%A0%E9%A3%9E%E9%A3%9E
将中文数据转成下面这种格式,叫做URL编码:
张飞飞 ---URL编码---> %E5%BC%A0%E9%A3%9E%E9%A3%9E
将下面这种格式再次转回中文数据,叫做URL解码:
%E5%BC%A0%E9%A3%9E%E9%A3%9E ---URL解码---> 张飞飞
∗Cookie导致的500异常∗
问题:当cookie中保存中文数据,将cookie添加到响应中时,会报一个500异常,
如下:
解决方法是:
(1)将存入cookie中的先进行URL编码,再存入Cookie中
(2)从cookie取出来的数据是进行URL编码后的数据,在使用之前需要进行URL解码:
10.3 Session
10.3.1 Session的工作原理
每次请求,都会检查 是否有 值为JSESSIONID 的cookie。
若没有这个cookie 或者根据这个cookie 没有找到相应的session,则视为第一次对话。
若是第一次对话,会创建session,并分配一个new cookie,键值分别为JSESSIONID 和 session 的索引。
- Session是将会话中产生的数据保存在<mark>服务器端</mark>,<mark>属于服务器端技术</mark>
- 一个浏览器在服务器端至<mark>多只对应一个</mark>Session对象。
当需要session时,如果服务器内部有当前浏览器对应的session,则不再创建,而是直接返回已有session。
如果没有对应session,才会创建一个新的session返回。 - <mark>通过session.setAttribute方法将数据保存在session域中</mark>
- <mark>通过session.getAttribute方法将数据从session中取出!</mark>
10.3.2 Session是一个域对象
Session是一个域对象,因此session中也提供了存取数据的方法。
Session.setAttribute(String attrName, Object attrValue)
-- 将属性保存到session域中,属性名只能是字符串,属性值可以是任意类型。
session.getAttribute(String attrName)
-- 根据属性名获取对应的属性值,返回值是Object类型
Session域对象的三大特征:
(1)生命周期:
创建session: 第一次调用request.getSession方法时,创建session对象。
或者当服务器中没有当前浏览器对应的session时,会创建一个新的session对象。
request.getSession();
request.getSession(true);
-- 上面两个获取session方法,其作用是:当服务器内部有session时,直接返回,当服务器内部没有为当前浏览器服务的session,就创建一个seession再返回。
request.getSession(false);
-- 而上面这个方法,其作用是:当服务器内部有session时,直接返回session,当服务器内部没有session,返回null。(即该方法只会返回现成的session对象,否则就返回null)
销毁session:
a)超时销毁: <mark>当session超过30分钟没有被访问时</mark>, session将会超时销毁。可以通过方法设置或者web.xml文件修改session的超时时间,但是一般我们不会修改。
b)***销毁: 当调用<mark>session.invalidate</mark>方法时, session会立即销毁。
c)意外身亡: 当服务器非正常关闭(硬件损坏、断电、结束服务器的进程等),session会随着服务器的关闭而销毁。
当服务器正常关闭时,session不会销毁。
在服务器关闭之前,会将服务器内部所有的session以文件形式序列化保存到硬盘上(保存在服务器的work目录下),这个过程叫做session的序列化或者钝化;
当再次打开服务器,文件还会在回到服务器变回对象。这个过程叫做session反序列化或者活化。
所以
∗∗注意∗∗
话题:
当浏览器关闭后,Session就销毁了吗?
答案:
存在于浏览器上的唯一标识符JSESSIONID(sessionid)消失了,但是服务器中存放的sessionid并没有立马销毁。
(2)作用范围:一次会话范围内
(3)主要功能:在一次会话范围内,实现数据的共享。
10.3.3 ∗∗Session获取不到的问题∗∗:30天内免登陆原理
将商品保存到session中后,<mark>关闭浏览器再打开浏览器</mark>,访问服务器,此时<mark>获取不到之前的session</mark>。
<mark>因为session是基于Cookie工作的</mark>。
<mark>在服务器创建一个session后,会为session分配一个独一无二的编号,称之为session的id</mark>,在此次响应时,<mark>服务器会将session的id以一个名称为 JSESSIONID的cookie发送给浏览器保存到浏览器内部</mark>。
由于保存sessionid的cookie默认的会话级别的cookie,
在浏览器关闭后,cookie销毁,sessionid也丢失了。因此下次访问服务器,没有session的id就获取不到之前的session。也获取不到session中的商品信息
解决方法:我们可以创建一个名称为JSESSIONID
的cookie,其中保存session的ID,并设置cookie的最大存活时间,让cookie保存到硬盘上(即使浏览器关闭,cookie也不会销毁),这样下次访问服务器时,还可以将sessionid带给服务器,服务器可以通过sessionid获取到之前的session。
从session
中获取到商品信息
10.4 总结:Cookie和session的区别
10.4.1 Cookie的特点
- cookie是将会话中产生的数据保存在浏览器客户端, 是<mark>客户端技术</mark>
- cookie是将数据保存在客户端浏览器,容易随着用户的操作导致cookie丢失或者被窃取,因此cookie中保存的数据不太稳定,也<mark>不太安全</mark>。
- cookie将数据保存在客户端,对服务器端没有太多影响,<mark>可以将数据保存很长时间</mark>。
<mark>因此cookie中适合存储需要长时间保存的数据,但对安全性要求不高。</mark> - 浏览器对cookie的大小和个数都有限制,一般推荐每一个站点给浏览器发送的cookie数量<mark>不超过20个</mark>,<mark>每一个cookie的大小不超过1kb</mark>。
<mark>Cookie的应用:实现购物车、记住用户名、30天内自动登录等。</mark>
10.4.2 Session的特点
- session是将会话中产生的数据保存在服务器端,是<mark>服务器端技术</mark>
- session将数据存在服务器端的session对象中,<mark>相对更加的安全</mark>,而且更加稳定。不容易随着用户的操作而导致session中的数据丢失或者是被窃取。
但session是服务器端的对象,在<mark>并发量较高时每一个浏览器客户端在服务器端都要对应一个session对象,占用服务器的内存空间,影响效率</mark>。
<mark>因此session中适合存储对安全性要求较高,但不需要长时间保存的数据。</mark>
<mark>Session的应用:保存登录状态、保存验证码</mark>