Cookie&Session学习笔记

一、会话技术

  • 1.会话:一次会话中包含多个请求和响应,由于HTTP协议是无响应的,所有每次请求都是独立的,无法共享数据。会话技术就是为了解决这个问题的。举个简单的例子,我们在淘宝购物,每一次点击一个商品加入购物车,我们选择了多个商品,每一次点击,都是一次独立的请求操作,然后最后我们去购物车付款,这也是一次独立的请求,但是我们可以在购物车页面看到我们刚才添加的商品,这就是利用会话技术实现的。
  • 2.一次会话指的是浏览器第一次给服务器资源发生请求,会话建立,直到有一方断开为止。
  • 3会话技术就是在一次会话的范围内的多次请求数据之间来共享数据
  • 4.方式
    • 1.客户端会话技术:Cookie,就是把共享数据保存在客户端
    • 2.服务端会话技术:Session,就是把共享数据保存在服务器

二、客户端会话技术Cookie

2.1Cookie的快速入门

  • 使用步骤
    • 1.创建Cookie对象,绑定数据:new Cookie(String name, String Value)
    • 2.发送Cookie对象:response.addCookie(Cookie cookie)
    • 3.获取Cookie对象,拿到数据:Cookie[] request.getCookies()
  • 实验:准备两个Servlet一个发送Cookie,一个获取Cookie
@WebServlet("/cookieDemo1")
public class CookieDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1.创建Cookie对象
        Cookie c  = new Cookie("msg", "hello");
        //2.发送Cookie
        response.addCookie(c);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
@WebServlet("/cookieDemo2")
public class CookieDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //3.获取Cookie
        // 因为可能获取多个嘛 所以有数组
        Cookie[] cs = request.getCookies();
        //遍历
        if (cs != null){
            for (Cookie cookie : cs) {
                String name = cookie.getName();
                String value = cookie.getValue();
                System.out.println(name + ":" + value);
            }
        }
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
  • 注意:
    • 必须先发送才能获取
    • 如果用谷歌浏览器访问Demo1发送Cookie,再用其他浏览器去访问Demo2获取Cookie,是获取不到的

2.2原理分析

  • 浏览器访问/cookieDemo1时,response会自动的在响应头里设置Cookie的相关信息,可以通过抓包观察到

在这里插入图片描述

  • 浏览器访问/cookieDemo2的时候,会在请求头里添加刚才的收到的Cookie数据,也可以很容易的在抓包工具里观察到:
    在这里插入图片描述
  • 整个过程可以用下图表示:
    在这里插入图片描述
  • 小结:基于响应头set-cookie和请求头cookie实现

2.3Cookie的细节

2.3.1一次可不可以发送多个Cookie?

  • 可以
  • 直接设置多个Cookie即可,在响应头里多个键值对保存即可
//1.创建Cookie对象
Cookie c1  = new Cookie("msg", "hello");
Cookie c2 = new Cookie("name", "zqx");
//2.发送Cookie
response.addCookie(c1);
response.addCookie(c2);

2.3.2cookie在浏览器存活多长时间?

  • 默认情况下,cookie存放在浏览器的内存中,当浏览器被关闭,cookie数据被销毁
  • 可以设置cookie信息持久化存储:
    • setMaxAge(int seconds)
      • 正数:将cookie数据写入硬盘中,持久化存储,并指定cookie存活时间,时间到后,文件自动失效
      • 零:删除cookie信息
      • 负数:就是默认情况
        //1.创建Cookie对象
        Cookie c1  = new Cookie("msg", "hello");
        //2.设置cookie的存活时间
        //2.1持久化到硬盘 30s后失效
//        c1.setMaxAge(30);
        //2.2 设置-1 就是默认请教
//        c1.setMaxAge(-1);
        //2.3设置0 删除cookie信息
        c1.setMaxAge(0);
        //2.发送Cookie
        response.addCookie(c1);

2.3.3 cookie可以存中文吗?

  • tomcat8之前的版本cookie不能直接存储重温
    • 需要将中文数据转码–一般采用URL编码(%E3)
  • 在tomcat 8 之后,cookie支持中文数据。特殊字符(空格)还是不支持,建议使用URL编码存储,URL解码解析

2.3.4cookie共享问题?

  • 1.在同一个tomcat服务器下,部署了多个web项目,这些项目之间的cookie可以共享吗?

    • 默认情况下不能共享
    • setPath(String path) : 设置cookie的获取范围。默认情况下,设为为当前的虚拟目录,那么就只能在当前的项目内进行共享,如果要在不同的项目间共享,则设置为:
    • setPath("/")
  • 2不同的服务器之间的web项目的cookie可以共享吗?

    • 可以的
    • setDomain(String path):如果设置一级域名相同,那么多个服务器之间cookie可以共享
      • setDomain(".baidu.com"),那么tieba.baidu.comnews.baidu.com中cookie可以共享

2.4cookie的特点和作用

  • cookie的数据存储在客户端浏览器
  • 浏览器对于单个cookie的大小有限制(4kb)以及对同一个域名下的cookie的数量也有限制(20)

在这里插入图片描述

  • cookie一般用于存储少量不太敏感的数据
  • 多用于在不登录的情况下,完成服务端对客户端的身份识别
    • 例如在登录百度的情况下可以对百度的搜索进行一些设置
    • 而且在重启浏览器后访问百度,这个设置依然有效

三、cookie案例:记住上一次的访问时间

1.需求

  • 1.访问一个Servlet,如果是第一次访问,则提示:您好,欢迎首次访问
  • 2.如果不是第一次访问,则提示:欢迎回来,您上一次的访问时间是:显示时间字符串

2.分析

  • 可以利用cookie来完成
  • 在服务器中有一个Servlet来判断是否有一个名为lastTimecookie
    • 1.没有:第一次访问
      • 首先响应数据:您好,欢迎首次访问
      • 其次回写cookie:lastTime = 当前时间
    • 2.有:
      • 首先响应数据:您上一次的访问时间是:显示时间字符串
      • 其次回写cookie:lastTime = 当前时间
        在这里插入图片描述

3.代码实现

整体逻辑简单,两个注意实现

  • cookie的name相同的话,会自动覆盖掉
  • cookie默认不支持特殊字符,例如空格,会发生HTTP-500报错,使用URL编码解码进行结局

3.1代码

package com.zqx.cookie;

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.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 20190816
 * 利用cookie实现访问时间的显示与存储
 */
@WebServlet("/cookieTest")
public class CookieTest extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //0.设置响应消息体的数据格式以及编码
        response.setContentType("text/html;charset=utf-8");
        boolean flag = false; //默认没有访问过
        //1.获取所有cookie
        Cookie[] cookies = request.getCookies();
        //2.遍历
        for (Cookie cookie : cookies) {
            //3.获取每一个cookie的name
            String name = cookie.getName();
            //4.判断name是否为指定的cookie名字 lastTime
            if ("lastTime".equals(name)){
                //有 说明不是第一次访问
                flag = true;
                //先获取当前的值
                String value = cookie.getValue();

                //设置cookie的value 会自动覆盖
                //获取当前时间的字符串 设置cookie 然后发生
                Date date = new Date();
                //时间格式化输出
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                String date_value = sdf.format(date);
                //为了解决 时间字符串的空格 无法被cookie直接识别的问题 进行URL编码和解码
                System.out.println("编码前:" + date_value);
                //URL编码
                date_value = URLEncoder.encode(date_value, "utf-8");
                System.out.println("编码后:" + date_value);

                //设置cookie值
                cookie.setValue(date_value);
                //设置存活时间 一个月
                cookie.setMaxAge(60 * 60 * 24 * 30);
                // 发生cookie
                response.addCookie(cookie);


                //响应 检测到有cookie 应取出当前的值(上一次访问时间)
                //同样这里也是经过URL编码的 所以先解码
                System.out.println("解码前:" + value);
                value = URLDecoder.decode(value, "utf-8");
                System.out.println("解码后:" + value);
                //回写到界面
                response.getWriter().write("<h1>欢迎回来,您上次访问时间为:"+value+"</h1>");

                //只要访问到想要的cookie后面则不再循环
                break;
            }
        }


        if (cookies == null || cookies.length == 0 || !flag ){
            //没有名为 lastTime的cookie 则第一次访问
            Date date = new Date();
            //时间格式化输出
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String date_value = sdf.format(date);
            //为了解决 时间字符串的空格 无法被cookie直接识别的问题 进行URL编码和解码
            System.out.println("编码前:" + date_value);
            //URL编码
            date_value = URLEncoder.encode(date_value, "utf-8");
            System.out.println("编码后:" + date_value);

            Cookie cookie = new Cookie("lastTime", date_value);
            cookie.setMaxAge(60 * 60 * 24 * 30);
            // 发生cookie
            response.addCookie(cookie);

            response.getWriter().write("<h1>您好,欢迎您首次访问</h1>");

        }

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

3.2效果

在这里插入图片描述

四、Session

保存在服务端的一次会话的共享数据

4.1快速入门

  • 1.获取HttpSession对象:HttpSession session = request.getSession();
  • 2.使用HttpSession对象:
    • Object getAttribute(String name) ;
    • void setAttribute(String name, Object value);
    • void removeAttribute(String name)
@WebServlet("/sessionDemo1")
public class SessionDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取Session对象
        HttpSession session = request.getSession();
        //2.设置数据
        session.setAttribute("msg", "hello session");


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
@WebServlet("/sessionDemo2")
public class SessionDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取Session对象
        HttpSession session = request.getSession();
        //2.获取数据
        Object msg = session.getAttribute("msg");
        System.out.println(msg);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

4.2原理

Session的实现是依赖Cookie的

  • 浏览器在第一次访问sessionDemo1的时候,服务器内存里没有Session对象,则会创建一个Session对象,并为其分配一个唯一的ID

  • 浏览器第二次访问sessionDemo2的时候,获取到Session对象,关键问题在于?如何确保第二次获取到的session和上一次是通一个Session对象呢?

    • 第一次服务器响应的时候会在响应头里写入SessionID信息:set-cookie=JSESSIONID=2323819319
    • 第二次浏览器发送请求的时候,会在请求头里包含该set-cookie=JSESSIONID=2323819319的信息
    • 服务器就是这样确保两次访问的session是同一个对象的
    • 可以看到,这个过程是通过把sessionID保存在cookie中完成的
  • 下面通过抓包可以看到这两个过程:
    在这里插入图片描述
    在这里插入图片描述

4.3 细节

4.3.1当浏览器关闭,服务器不关闭,两次获取的Session是否为同一个?

  • 默认情况下不是同一个,因为浏览器关闭了,意味着当前会话已经结束了嘛
    • 获取一个Session,打印其地址,然后两次访问该Servlet
      在这里插入图片描述
      在这里插入图片描述

    • 如果需要相同,则可以创建cookie,然后设置键JSESSIONID,设置最大存活时间,让cookie持久化保存。

 //1.获取Session对象
        HttpSession session = request.getSession();
        //2. 使用Cookie持久化session 让关闭浏览器后 获取到的Session为同一个
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setMaxAge(60 * 60);
        response.addCookie(cookie);
       //2.打印session的内存地址
        System.out.println(session);
    }

在这里插入图片描述

4.3.2客户端不关闭,服务器关闭后,两次获取的Session是同一个吗?

  • 不是同一个,因为服务器关闭后,web项目的内存空间肯定也关闭了,Session信息肯定丢失了。

  • 但是这个Session的数据又很重要,需要想办法确保服务器关闭后也能保存下来。

  • 例如,用户在淘宝刚刚加入了很多商品在购物车,这个购物车的信息就是保存在session中的,如果服务器关闭了,且session数据没有被保存,那么购物车的信息也就被丢失了。

  • 所以,为了解决上述问题,tomcat服务器会自动的完成以下工作:

    • session的钝化:在服务器正常关闭之前,将Session对象系列化到硬盘上
    • session的活化:在服务器启动后,将session文件反序列化为内存中的Session即可
    • 但是要注意这种方法仅仅在手动部署项目到tomcat服务器才生效,使用IDEA联合配置是不生效的
    • 至于为什么,下面通过实验来说明
  • 1.首先找到当前项目部署在tomcat目录下的out文件
    在这里插入图片描述

  • 2.将其打包成.war的文件
    在这里插入图片描述

  • 3.将打包后的文件放在本地的tomcat的web-apps目录下
    在这里插入图片描述

  • 4.启动本地的tomcat项目(bin/startup.bat),发现刚才打包的项目被自动部署
    在这里插入图片描述

  • 访问其中的一个Servlet
    在这里插入图片描述

  • 正常关闭tomcat(/bin/shutdown.bat),观察work目录下的项目目录
    在这里插入图片描述-可以发现生成了一个Session文件,接下来,再次手动启动tomcat,观察现象
    在这里插入图片描述

  • 发现.ser文件消失,这是因为被自动加载到内存中去了

  • 这个例子很清楚了说明了tomcat自动保存和加载session的过程

  • 那么为什么IDEA不行呢?

  • 先说结论,在IDEA中正常关闭服务器后,仍然会自动保存

  • 但是重启服务器后,IDEA会自动删除work目录,再新建,自然session.ser也被删除了

4.3.3session何时被销毁

  • 1.服务器关闭
  • 2.session对象调用invalidate()
  • 3.选择性配置修改
<session-config>
    <session-timeout>30</session-timeout>
 </session-config>

在这里插入图片描述

4.4session特点

  1. session用于存储一次会话的多次请求的数据,存在服务器端
    • 常用在重定向的时候共享数据,ServletContex也可以用于重定向的数据共享,但是它的范围太大了
  2. session可以存储任意类型,任意大小的数据
  3. session与Cookie的区别:
    1. session存储数据在服务器端,Cookie在客户端
    2. session没有数据大小限制,Cookie有
    3. session数据安全,Cookie相对于不安全
  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值