Javaweb之cookie和session
Cookie和Session
在web开发阶段,我们主要是浏览器和服务器之间来进行交互。浏览器和服务器之间的交互就像人和人之间进行交流一样,但是对于服务器端和浏览器端来说,不会这么智能。因为对于机器来说,在一次请求之间只是会携带着本次请求的数据的,但是可能多次请求之间是会有联系的,比方说这一次的请求需要使用到上一次请求的某些信息等,所以提供了会话机制。
在用户打开浏览器,对多个服务器端进行请求,直到将用户将浏览器进行关闭,在这一阶段,这个过程称之为会话。
在进行会话(可能是多次请求)期间,浏览器和服务器端会产生交互的数据,而有些数据是需要我们在下次请求中需要使用到的,所以我们可能需要将当前的数据来进行保存,在下次请求的时候在携带过去。而实现这一功能可以通过会话技术来进行实现。
所以会话技术的作用就很明显了:保存用户的数据
常用的会话技术分为两种:Cookie和Session技术
对于Cookie来说,是浏览器端的技术,数据是以k-v的形式保存到浏览器端的。如果没有关闭浏览器,再次请求服务器,浏览器会把cookie信息携带到服务器端,服务器端拿到对应的数据,可以进行再次处理。
而且cookie是有生命周期的
默认的cookie的生命周期是在浏览器打开阶段到关闭期间这一段时间,一旦关闭了浏览器,那么当前的cookie的生命周期结束;
但是我们可以设置,默认的是在浏览器关闭之后,cookie就消失了,这个时候cookie是在内存中的,我们可以将其保存到硬盘中去,待到下次打开浏览器的时候,再从硬盘中来进行读取cookie的信息到内存中去,然后让浏览器携带指定的cookie信息到服务器端去。
对于Session来说,是服务器端的技术。用户使用浏览器和服务器进行交互的数据是可以保存到服务器端的,
而对于服务器来说,会为每个浏览器端开辟一块内存空间来保存对应的信息,即session。
服务器端为每个浏览器器创建的内存空间是每个浏览器端所独享的,也就是session对象,那么服务器端会为每个浏览器的session创建一个唯一的标识,也就是sessionid,服务器端会将sessionid写到到cookie中去,正如上面介绍的cookie,浏览器再次请求的时候会携带cookie,服务器端取出来对应的sessionid之后,服务器端就可以根据sessionid来找到对应的session对象,然后找到对应的session对象中保存的信息。
所以说session是依赖于cookie存在的。
通过这里的介绍,相信也可以看出来,为什么以后会使用Redis、Session等第三方工具来进行使用了。
一、tomcat中的session占用内存,尽管也有生命周期;
二、通过唯一标识来进行标注是哪个用户;
三、效率问题
1、cookie的概念
官方API介绍:
创建一个 cookie,cookie 是 servlet 发送到 Web 浏览器的少量信息,这些信息由浏览器保存,然后发送回服务器。cookie 的值可以唯一地标识客户端,因此 cookie 常用于会话管理。
一个 cookie 拥有一个名称、一个值和一些可选属性,比如注释、路径和域限定符、最大生存时间和版本号。一些 Web 浏览器在处理可选属性方面存在 bug,因此有节制地使用这些属性可提高 servlet 的互操作性。
servlet 通过使用 HttpServletResponse#addCookie 方法将 cookie 发送到浏览器,该方法将字段添加到 HTTP 响应头,以便一次一个地将 cookie 发送到浏览器。浏览器应该支持每台 Web 服务器有 20 个 cookie,总共有 300 个 cookie,并且可能将每个 cookie 的大小限定为 4 KB。
浏览器通过向 HTTP 请求头添加字段将 cookie 返回给 servlet。可使用 HttpServletRequest#getCookies 方法从请求中获取 cookie。一些 cookie 可能有相同的名称,但却有不同的路径属性。
cookie 影响使用它们的 Web 页面的缓存。HTTP 1.0 不会缓存那些使用通过此类创建的 cookie 的页面。此类不支持 HTTP 1.1 中定义的缓存控件。
此类支持版本 0(遵守 Netscape 协议)和版本 1(遵守 RFC 2109 协议)cookie 规范。默认情况下,cookie 是使用版本 0 创建的,以确保最佳互操作性。
从上面可以提取出来一些重要关键词:
servlet发送到web浏览器端的少量信息;
浏览器保存,然后发送到服务器;
cookie的值可以唯一标识一个客户端;
cookie组成:名称、值、可选属性(路径、最大生存时间)
使用:
设置:
servlet 通过使用 HttpServletResponse#addCookie 方法将 cookie 发送到浏览器,该方法将字段添加到 HTTP 响应头,以便一次一个地将 cookie 发送到浏览器。浏览器应该支持每台 Web 服务器有 20 个 cookie,总共有 300 个 cookie,并且可能将每个 cookie 的大小限定为 4 KB。
获取:
浏览器通过向 HTTP 请求头添加字段将 cookie 返回给 servlet。可使用 HttpServletRequest#getCookies 方法从请求中获取 cookie。一些 cookie 可能有相同的名称,但却有不同的路径属性。
默认的生命周期:
1、出生在服务器端。
2、第一次由response对象发送过来,保存在浏览器端;期间可以多次进行交互,可以修改。类似于service方法
可以多次被调用。
3、销毁。浏览器关闭的时候
类似于servlet,也有其特殊的操作。可以设置生命周期的时长,摆脱浏览器而存在于本地中。
Cookie是一种客户端的会话技术,它是服务器存放在浏览器的一小份数据,浏览器以后每次访问该服务器的时候都会将这小份数据携带到服务器去。
说明了一个问题,不能存放较多的数据。只能存放较少的数据。
2、cookie作用
1、在浏览器中存储数据
2、当浏览器再次访问相同的网站的时候,会将存储在浏览器中的一份小数据带过去
3、cookie使用
- 创建一个Cookie对象(cookie只能保存字符串数据。且不能保存中文)
new Cookie(String name,String value); // 两个都是String数据类型的
- 服务器端利用response将cookie写回浏览器
response.addCookie(cookie);
- 获得浏览器带过来的所有Cookie:
request.getCookies() ; //得到所有的cookie对象。是一个数组,开发中根据key得到目标cookie
- cookie的 API
cookie.getName() ; //返回cookie中设置的key
cookie.getValue(); //返回cookie中设置的value
演示一个案例:
@WebServlet("/cookieOne")
public class CookieServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
this.doGet(request,response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取cookie是request的功能
// 获得所有的cookie。第一次过来的时候不会携带什么的cookie。控制台什么都没有
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
// 获取得到cookie的名字
if("akey".equals(cookie.getName())){
// 获取得到cookie的名字
System.out.println(cookie.getValue());
}else {
//创建两个Cookie
Cookie aCookie = new Cookie("akey", "aaa");
Cookie bCookie = new Cookie("bkey", "bbb");
//写给浏览器
response.addCookie(aCookie);
response.addCookie(bCookie);
}
}
}
}
}
观察控制器,可以看到打开浏览器后,第一次访问的时候,控制台没有任何数据;在第二次进行访问的时候产生了数据;
再次关闭后打开,还是一样的结果。
4、设置cookie的生命周期
默认的是在浏览器关闭的时候,cookie消失,通过上面的案例中可以观察到。
setMaxAge(int expiry) // 设置生命期限,单位是秒
expiry如果是-1,默认值
expiry如果是0,删除cookie
expiry如果是正数,表示存活多少秒
@WebServlet("/cookieTwo")
public class CookieServletTwo extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
this.doGet(request,response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取cookie是request的功能
// 获得所有的cookie。第一次过来的时候不会携带什么的cookie。控制台什么都没有
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
// 获取得到cookie的名字
if("akey".equals(cookie.getName())){
// 获取得到cookie的名字
System.out.println(cookie.getValue());
}else {
//创建两个Cookie
Cookie aCookie = new Cookie("akey", "aaa");
Cookie bCookie = new Cookie("bkey", "bbb");
aCookie.setMaxAge(60*2);
//写给浏览器
response.addCookie(aCookie);
response.addCookie(bCookie);
}
}
}
}
}
5、设置cookie的路径
设置指定路径的cookie,当访问了指定的路径的时候,浏览器才会推送cookie过去。
cookie.setPath(String path)
当访问网站的时候,浏览器会将所有的该网站上的cookie都保存在请求协议包中的请求头中。
有效路径作用 :
- 保证不会携带别的网站/项目里面的cookie到我们自己的项目
- 如果路径不一样, cookie的key可以相同
- 保证自己的项目可以合理的利用自己项目的cookie
-
默认路径,例如:
- 访问http://localhost:8080/web18A_Cookie/demo01; cookie默认路径 /web18A_Cookie
-
访问http://localhost:8080/web18A_Cookie/aaa/demo01; cookie默认路径 /web18A_Cookie/aaa
-
访问http://localhost:8080/web18A_Cookie/aaa/bbb/demo01; cookie默认路径 /web18A_Cookie/aaa/bbb
-
随带Cookie需要的条件: 只有当访问资源的url包含此cookie的有效path的时候,才会携带这个cookie;反之不会.
-
eg: 设置cookie的路径 /demo02
下次访问路径:http://localhost:8080/day30a-cookie/demo02/ccc; cookie是可以带过来
下次访问路径:http://localhost:8080/day30a-cookie/demo03; cookie带不过来
-
-
cookie的路径通常设置 / 或者 /发布项目名设置的有效是 /day30a-cookie. 当前项目下的Servlet都可以使用该cookie. 一般这么设置: cookie.setPath(request.getContextPath());
只要是当前项目里面的资源 路径必须包含项目名路径.
建议设置成当前的项目部署路径,setPath(request.getContextPath())
案例演示:
需求:上一次的访问时间(首次访问不算)
分析过程:
- 1、第一次过来请求,那么肯定是没有cookie的
- 2、如果不是第一次,那么将最新的时间添加到cookie的value中。
对上面2中进行再次说明
1、再次设置生命时长和路径
2、再次设置路径。// 可以操作,也可以不必操作
为什么?相当于是再次创建了一个cookie,只不过创建出来的新的cookie是和原来cookie中的key是相同的,会进行覆盖。所以之前设置的cookie的路径是不会发生改变的
@WebServlet("/remember")
public class Remember extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 一般来说,我们都是在前面先处理请求, 然后在后面对这次请求作出相应
//在这里设置乱码
resp.setContentType("text/html;charset=utf-8");
//获取cookie
Cookie[] cookies = req.getCookies();
if(cookies != null){
//表示不是第一次来 , 那么表示有cookie,此时要遍历所有的cookie
for(Cookie c : cookies){
String name = c.getName();
if("last".equals(name)){
String value = c.getValue();//
//2. 构建日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//3. 使用毫秒值,创建一个日期对象
Date date = new Date(Long.parseLong(value));
// date.setTime(Long.parseLong(value));
//4. 根据格式来格式化的日期。
value = sdf.format(date);
resp.getWriter().write("您上次访问的时间是:" +value);
}
}
}else{
//表示是第一次来。
resp.getWriter().write("您是第一次访问!");
}
//不管是第几次来,永远要设置当前的时间,这里就设置当前的毫秒数
long time = System.currentTimeMillis();
Cookie cookie = new Cookie("last",time+"");
cookie.setMaxAge(1*60 *60 *24 * 7);
resp.addCookie(cookie);
System.out.println("返回cookie了");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
6、Session
Session是服务端的会话技术
session的执行原理:
1、服务器端从客户端中的cookie中获取得到sessionid;
2、如果从cookie中没有获取得到sessionid,那么则会创建出来session对象;
3、如果发现存在着sessionid,服务器端根据sessionid来找到指定的session对象
如果sessionid存在,session对象也存在,那么直接使用;
如果sessionid存在,而session对象消失了,则执行第二个步骤;
对应的示意图如下所示:
6.1、session使用
范围: 会话(多次请求),用来保存用户各自的数据(以浏览器为单位)
- request.getSession(); 获得session(如果第一次调用的时候其实是创建session,第一次之后通过sessionId找到session进行使用)
- Object getAttribute(String name) ;获取值
- void setAttribute(String name, Object value) ;存储值
- void removeAttribute(String name) ;移除
7、session和cookie比较
session是需要依赖于cookie的,而对于cookie来说,默认的生命周期是在浏览器关闭之后,cookie消失,那么下次再次访问的时候,cookie中携带的sessionid就消失了。sessionid消失了,那么再次去进行请求的时候,就会重新创建一个新的session对象,那么就失去了对应的效果了,所以要想使用原来的session,那么首先需要保证关闭浏览器之后,再次进行请求的时候会携带sessionid,所以这个时候需要设置cookie的有效时间。
所以这个时候,我们如果需要手动的设置session的话,那么我们可以获取得到session的id,然后将其保存到cookie中去,需要注意的是cookie的key必须要是JESSIONID.
对于cookie和session来说,都是k-v结构,但是cookie的值只能够是字符串,而session的value是Object类型,说明可以存放任意类型的值。
7、三大域对象的比较
域对象 | 创建 | 销毁 | 作用范围 | 应用场景 |
---|---|---|---|---|
ServletContext | 服务器启动 | 服务器正常关闭/项目从服务器移除 | 整个项目 | 记录访问次数,聊天室 |
HttpSession | 没有session ,调 用request.getSession()方法 | session过期(默认30分钟)/调用invalidate()方法/服务器异常关闭 | 会话(多次请求) | 验证码校验, 保存用户登录状态等 |
HttpServletRequest | 来了请求 | 响应这个请求(或者请求已经接收了) | 一次请求 | servletA和jsp(servletB)之间数据传递(转发的时候存数据) |