一、cookie / session 应用场景
1. 服务器识别记录用户状态
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要使用某种机制来识别具体的用户,这个机制就是Session。典型的场景比如购物车,当点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建特定的Session,用于标识这个用户,并且跟踪用户,这样才知道购物车里面有什么商品。
这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件等。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如 Memcached 之类的来存放 Session。
2. 服务端如何识别特定的客户
这个时候Cookie就登场了,每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端,实际上大多数的应用都是用 Cookie 来实现Session跟踪的。第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。
有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx
这样的参数,服务端据此来识别用户。
3. 总结
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式;
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中。
二、会话
1. 会话的概念
会话是指一个客户端(浏览器)与Web服务器之间连续发生的一系列请求和响应过程,关闭浏览器会话结束。简单来说就是指浏览器从打开一直到关闭的这个阶段称作为一次会话(默认)。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。
2. 会话技术
为了保存会话过程中产生的数据,在 Servlet 中提供了Cookie和Session来保存跟踪数据。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
3. 会话结束
关闭浏览器上的tab页不算会话结束,只有关闭浏览器才算结束会话。
三、Cookie
1. 什么是Cookie?
Cookie是浏览器端的会话技术,它实际上是浏览器写在你本地计算机上的一个文本文件,大小不超过 4K。
当浏览器请求服务器时,如果服务器需要记录该用户状态,就生成一个Cookie通过响应发送到浏览器,浏览器会把Cookie保存起来。当浏览器再次请求该网站时,浏览器会把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。
2. Cookie什么时候产生?
访问 HTML 不产生Cookie,访问 JSP / Servlet 会产生 Cookie。
3. Cookie 的应用场景
- 记住用户名
- 自动登录(记住用户名和密码)
自动登录场景:当用户访问首页时,会先取得所有的 Cookie,然后一个个检查是否有Cookie 存储名称为 username 值为 xxx,名称为 password为 xxx,如果有,则表示先前用户登录时,曾选取自动登录选项,因此直接跳转欢迎页面。
4. API
1.Cookie
Cookie(String name, String value) 创建 cookie 对象
cookie.setMaxAge(60*60*24*7); //7 天,单位秒s
String getName() 获取 cookie 的名称
String getValue() 获取 cookie 的值
void setPath(String url) 设置 cookie 的路径 — 浏览器根据这个路径判断哪些 cookie 要发送给服务器
2. HttpServletResponse:
void addCookie(Cookie cookie) 将 cookie 发送给浏览器
3. HttpServletRequest:
Cookie[] getCookies() 获取浏览器发送的 cookie
5. 使用步骤
- 在
CookieServlet1
中创建 cookie - 在
CookieServlet1
设置 cookie 路径为当前项目根路径:"/HelloCookie"
- 在
CookieServlet1
使用 response 对象将 cookie 发送给浏览器 - 在
CookieServlet2
通过 request 对象获取浏览器发送的 cookie - 打印在控制台上
CookieServlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//往 cookie 里面写入数据
Cookie cookie = new Cookie("username","admin");
//cookie 设置有效期
cookie.setMaxAge(60*60*24*7);//7 天,
//设置 cookie 的路径——浏览器根据这个路径判断哪些 cookie 要发送给服务器,路径格式:/工程名字/资源路径
//需求: 只访问 GetCookieDataServlet 开头的,浏览器才携带 cookie
cookie.setPath(request.getContextPath()+"/GetCookieDataServlet");
//将 cookie 发送给浏览器
response.addCookie(cookie);
}
CookieServlet2:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//HttpServletRequest对象 getCookies(),获取浏览器发送的 cookie
Cookie[] cookies = request.getCookies();
//判断数据有效性
if(cookies!=null){
//遍历 cookies 数组读取里面的数据
for(Cookie cookie : cookies){
//获取 cookie 里面存储 name 为 username 的数据
if(cookie.getName().equals("username")){
response.getWriter().write(cookie.getName()+":"+cookie.getValue());
}
}
}
}
6. 删除/修改 Cookie
删除:新建一个 Cookie 对象使重名,设置生存时间为0,并设置Cookie路径与要删除Cookie路径一致,发送 Cookie给浏览器覆盖已有 Cookie;
修改:新建一个 Cookie 对象使重名(重新设置value),设置Cookie路径与要修改Cookie路径一致,发送 Cookie给浏览器覆盖已有 Cookie。
注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。
7. Cookie 特点
- 一个 Cookie 对象存储一个键值对,且 Cookie 存储的值必须是 String 类型
- Cookie 是通过响应头传递给浏览器存储的,
Set-Cookie: username=admin...
- Cookie 存储在浏览器缓存目录中的一个文本文件
- Cookie 如果没有设置最大有效时间,浏览器缓存目录不会产生文本文件,Cookie 数据只会保留在浏览器内存中,当浏览器一旦关闭,Cookie的数据会马上丢失;
- Cookie 如果没有设置有效路径,那么有效路径默认为当前的工程名,
/工程名
; - Tomcat8 开始 Cookie 允许中文的数据存在,但是不允许
空格 = , ;
这些字符存在,如果需要存在这些特殊字符,需要进行URL编码。
8. Cookie 总结
服务器端生成 Cookie 数据,通过响应头传递给浏览器,存储在浏览器端缓存目录下的文本文件中。浏览器每次请求都会携带与 Cookie 有效路径开头的的 Cookie 数据,通过请求头带到服务器端。Cookie 存储在客户端,数据是不安全的,对于敏感数据要进行加密后再存储,Cookie 文件大小有限制:4KB。
四、Session
1. 什么是Session ?
Session 是服务器端会话对象,是服务器为每个浏览器(每个用户)创建的单独私有的存储空间。Session是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器内存里单独的存储空间,这就是Session。客户端浏览器再次访问时只需要从该 Session 中查找该客户的状态就可以了。
2. 应用场景
- 保存用户登录信息数据
- 保存验证码
- 保存用户浏览器记录数据
- 保存购物车数据
3. Session特点
- 运行在服务器端,由服务器为每个浏览器创建单独的存储空间对象,称为服务器会话对象。
- 每个用户都有自己的会话对象,不同的浏览器代表不同的用户。
- 会话对象也是一个域对象,主要用于在服务器端存储每个用户自己的数据,不同的用户之间数据不能共享。
4. API
1.HttpServletRequest
HttpSession getSession() 获取 session 对象
2.HttpSession
void setAttribute(String name, Object value) 在 session 中保存数据
Object getAttribute(String name) 从 session 中获取数据
void removeAttribute(String name) 从 session 中移除数据
5. 使用步骤
- 在
AddSessionServlet
中通过 request 对象获取 Session 对象 - 调用 Session 的 setAttribute 方法保存数据到 Session 中
- 调用 session 的 getAttribute 获取数据
- 在
GetSessionServlet
通过 request 对象获取 session 对象 - 在
GetSessionServlet
调用 session 的 removeAttribute 移除数据 - 在
GetSessionServlet
调用 session 的 getAttribute 获取数据
AddSessionServle:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取服务器创建session
HttpSession session = request.getSession();
//存储数据
session.setAttribute("loginUser","admin");
//每个 session 都有一个唯一的 sessionid,用于标识唯一的 session 对象
response.getWriter().write("session write ok,sessionid= " + session.getId());
}
GetSessionServle:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//获取session中保存数据
Object object = session.getAttribute("loginUser");
if(object!=null){
String loginUser = object.toString();
response.getWriter().write("loginUser=" + loginUser);
}else{
response.getWriter().write("no data");
}
}
6. 工作原理
尝试运行HttpServletRequest的getSession()
时,Web容器会创建 HttpSession 对象,关键在于每个 HttpSession 对象都会有个特殊的ID,称为 Session ID,可以执行HttpSession 的 getId()来取得 Session ID。这个 Session ID 默认使用 Cookie 存放在浏览器中。在Tomcat中,Cookie的名称是JSESSIONID,数值则是getId()所取得的Session ID。
由于Web容器本身是执行于JVM中的一个Java程序,通过getSession()取得HttpSession,是Web容器中的一个Java对象,HttpSession中存放的属性,自然也就存放于服务器端的Web容器之中。每一个 HttpSession 各有特殊的Session ID,当浏览器请求应用程序时,会将Cookie中存放的Session ID一并发送给应用程序,Web容器会根据Session ID来找出对应的HttpSession对象,这样就可以取得各浏览器个别的会话数据。
默认关闭浏览器会马上失效的是浏览器上的Cookie,不是 HttpSession。因为Cookie失效了,就无法通过Cookie来发送Session ID,所以关闭浏览器再打开尝试getSession()时,容器会产生新的HttpSession。而要让HttpSession立即失效必须运行invalidate()
方法。否则的话,HttpSession 会等到设定的失效期过后才会被容器销毁回收。
7. 生命周期
Session 的有效期是一次会话内,关闭了浏览器 Session 数据就丢失了,但是 Session 对象依然存储在服务器内存中。由于有越来越多的用户访问服务器,每个用户都会有一个独立的 Session,因此 Session 会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的 Session 从内存删除。这个时间就是Session的超时时间,如果超过了超时时间没访问过服务器,Session就自动失效了。
Session 在用户第一次访问服务器时自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、Image等静态资源并不会创建Session。如果尚未生成Session,也可以使用 request.getSession(true)
强制生成 Session。Session生成后,只要用户继续访问,服务器就会更新 Session 的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的 Session "活跃(active)"
了一次。Session 默认有效期 30 分钟,距离最后一次请求超过 30 分钟,Session 就自动过期。
改变Session有效时期
1)通过 Tomcat下conf/web.xml
配置
<!-- 配置会话的时间,以分钟为单位 -->
<session-config>
<session-timeout>100</session-timeout>
</session-config>
session-timeout,如果设置为 0 或负数,则会话不过期,但受限于服务器的内存空间
注意: 一般没有人会去更改 session 默认 30 分钟有效期
2)invalidate()
应用场景,注销登录,让 session 立刻过期
session.invalidate();
session.removeAttribute(“loginUser”); 也可以
五、Cookie 和 Session 的区别
比较 | Cookie | Session |
---|---|---|
数据保存的位置 | 浏览器 | 服务器 |
存储数是否有限制 | 有(4kb) | 无 |
数据的安全性 | 不安全 | 安全 |
服务器压力 | 小 | 大 |