Cookie和Session

时间:2022-08-01 01:12:36

Cookie和Session区分

1. 会话控制技术

​ 浏览器和服务器之间数据的访问的形式,以及响应的形式都是通过一来一回。如果浏览器发送新的请求和之前的请求没有任何关系。可以使用会话控制技术存储浏览器和服务器之间的交互【核心】信息,之后的浏览器访问服务器可以在对应的【核心】信息中间提交必要内容,简单用户操作逻辑。

​ 会话控制技术主要组成部分是 Cookie and Session可以用于: 自动登陆,IP地址变化提示,上一次访问时间记录。

1.1 使用会话控制的原因

​ HTTP 协议是一个无状态的协议。一个用户向服务器发出请求,然后服务器返回响应,在服务器端不保存任何有关联的信息,因此在下一次的连接的时候,服务器已经没有以前的连接的信息了,无法判断这次的练级而是否和以前的连接属于同一个用户。

​ 浏览器每一次访问服务器,服务器无法知道当前的浏览器访问之前做过什么,不管是浏览器,还是服务器都没有对数据进行保存。

1.2 状态管理

​ web application 会话过程中,浏览器和服务器直接的一次响应和请求就是一次会话,这里需要管理和操作的就是在浏览器和服务器直接交互的过程中,产生无状态的信息,这里可以利用会话控制技术,保存一些浏览器和服务器交互的核心的数据。

​ 可以减少浏览器请求的次数,同时降低服务器处理业务逻辑的压力。并且可以将浏览器的请求和服务器的响应连接到一起。

1.3 核心操作技术

Cookie 客户端保存数据会话的方式。

Session 浏览器保存会话数据的方式

2. Session对象

​ Tomcat 能够使用内置对象记录有关的连接信息。内置对象Session 通过Tomcat 服务器负责创建,Session是实现了HttpSession接口类的一个实例。

【重点】

​ session 是保存在服务器端的一个会话控制对象,保留浏览器访问当前服务器提供的资源和必要的信息。允许浏览器多次的访问情况下,都能够获取到对应的session 信息。

​ session数据

  1. 服务器保存session 数据没有限制。
  2. session存储数据的方式是键值对形式,键是String类型,但是值可以是任意的类型。session可以看做是一个Map双边的队列 HashMap<String ,Object>。
  3. 中文的问题。
  4. 数据量也是没有问题的,但是需要有一定的限制。

2.0 Session 工作原理

Session 会话的技术是依赖于Cookie

  1. 浏览器第一次访问对应的服务器,服务器会根据当前访问的时间,其他参数生成一个Session ID号,这个Session ID 是不能够进行重复的。
  2. 利用Cookie 技术,服务器将Session ID 号发送给浏览器保存。
  3. 浏览器第二次访问对应的服务器,会带有Session ID 号的Cookie 访问对应的资源,服务器能够根据Session ID 找到对应的Session ,从Session 获取对应的数据。
  4. 浏览器如果关闭 Cookie 的技术,Session 使用的时候会非常的麻烦,需要利用URL重写的技术。
  5. 浏览器本地保存Session ID 的cookie JSESSIONID 名字固定。

2.1 session对象的id

场景重现:

​ 当一个用户首次访问web 服务目录中的一个页面的时候,Tomcat服务器产生一个session对象,这个session对象调用相应的方法可以存储用户再去爱访问Web服务目录中各个页面期间提交的各种数据信息,比如姓名、性别等信息。

​ 此时Session对象被分配了一个String类型的ID,Tomcat服务器同时将这个id号发送到用户端,存放在用户的Cookie中。 在这种情况下,Session对象和用户之间建立一对一的对应的关系,即每一个用户都对应着一个Session对象,不用的Session对象互不相同,具有不同的id号码。当用户再次访问该页面的时候,Tomcat 将不会再次创建新的session对象,而是使用完全相同的一个,知道session对象达到了最大的生存的时间或者服务器关闭状态。服务器取消用户的Session对象,即和用户的会话对应的关系消失。当用户重新连接到该页面的时候,服务器会再次创建一个新的Session对象。

​ 总结: 在用户访问页面的时候,会创建一个Session对象,服务器可以在各个页面使用这个Session记录当前的用户的相关的信息。服务器保证不同的用户的Session对象互不相同。

2.2 session 对象与URL重写

​ session 对象是否能够与用户建立起一一对应的关系以来于用户端是否能够支持Cookie.如果用户端不支持Cookie ,那么用户在不同的网页之间的session对象可能是相互不相同的,因为服务器无法将ID存放到用户端,就不能够建立Session对象和用户的一一对应的关系。如果浏览器关闭Cookie的设置,上述的情况就会发生改变,也就是说:同一个用户对应了多个session 对象,这样服务器就无法知道在这些页面*问的实际上是同一个用户。

​ 如果用户端不支持Cookie,JSP页面可以通过URL重写来实现session对象的唯一性,所谓的URL重写,就是当用户从一个页面重新连接到另外的一个页面的时候,通向这个新的URL添加参数,把session 对象的id 传输过去,这样就可以保证用户在网站各个页面中的session对象是完全相同的。可以使用response 对象调用 encodeURL() 或者encodeRedirectURL() 方法实现URL重写操作。

2.3 session对象存储数据

​ session 对象会驻留在服务器端,该对象在调用某些方法保存用户在访问某个web服务目录期间的有关的数据。当session对象处理数据的时候,非常类似一个购物车,一个用户访问一个商场的时候,类似于一个web服务目录,可以将商品放到购物车中,也能够将之从购物车中拿出来。

方法 概念
void setAttribute(String key,Object obj) session 对象可以调用该方法将参数Object指定的对象添加到session对象中,并且为添加的对象指定一个索引的关键字。如果添加的两个对象的关键字相同,则先前添加的对象被清除。
Object getAttribute(String key) 获取session对象索引的关键字是key 对象,由于任何对象都能够添加到session对象中,因此使用该方法获取对象的时候,应该使用强制类型转换的类型。
void removerAttribute(String name) session 对象调用该方法关键字key 对应的对象。

2.4 session对象的生存周期

​ session 对象的生存周期依赖于session对象是否调用invalidate() 方法使得session对象无效或者session对象达到了设置的最长的发呆时间。session 对象使用setMaxInactiveInterval(int interval) 方法设置最长的发呆的状态时间,一般来说发呆的时间是30分钟。

2.5 HttpSession 方法

方法 功能
Request.getSession(); 然后存在对应当前请求的Session返回对应Session,如果没有创建一个新的Session
Request.getSession(boolean); 参数为true,获取对应请求的Session对象,如果没有创建一个新的Session。参数为false,只会获取对应当前请求的Session,没有返回null
String getId(); 获取当前Session ID号,ID不可以重复
long getLastAccessedTime() 获取上一次的访问时间
setMaxInactiveInterval(int interval); 设置当前Session有效时间,单位是秒数
long getMaxInactiveInterval(); 获取当前Session有效时间
long getCreationTime() 获取Session的创建时间
setAttribute(String name, Object value) 设置Session中存储的数据,键值对形式,String类型的键,值为Object类型
Object getAttribute(String name) 获取指定键值对应的Object数据
removeAttribute(String name) 删除对应的键值对
invalidate() 销毁Session对象

2.6 总结

对象的销毁

// 销毁对应的session对象
session.invalidate()

使用session 操作

// 如果有对应的session id 查询对应的session 对象,返回HttpSession 对象
// 如果没有对应的session id 查询不到对应的session 对象,会创建新的HttpSession。服务器会在浏览器端留下一个Cookie的信息,JSESSIONID 里面保存的是Session ID

HttpSession session = req.getSession();
sout(session.getID());
session.setMaxInactiveInterval(30)

3. Cookie 对象

3.1 概述

​ Cookie 是浏览器保存访问的WEB Application时留存的会话的数据,服务器会在浏览器访问指定的资源时,使用响应头发送一定的Cookie信息给浏览器保存,浏览器会存储对应的Cookie的数据,并且在下一次的访问对应的WEB Application自动带上对应的Cookie 数据,访问资源。

  1. Cookie 数据时通过Response 响应从Web Appincation 接受,响应头:Set -Cookie
  2. Cookie 数据会随着Request 请求从浏览器到对应的WEB Application 请求头中的Cookie
  3. 会根据Cookie 限制的有效的路径来选择对应的资源
  4. Cookie 的数据在浏览器中进行保存,有一定的限制,浏览器中保存的Cookie 个数总数限制在300左右,单一的站点问题限制的Cookie的个数是20个,单一的Cookie 的数据大小是在4KB的范围之内,单一的Cookie 形式是通过键值对的形式进行创建的,有name 和 value ,并且不支持中文。

3.2 方法

方法 功能呢
Cookie(String name, String value) 服务器创建一个Cookie对象
setPath(String path) Cookie数据的有效路径
setMaxAge(int time) Cookie的有效时间
Cookie[] Request.getCookies(); 获取当前请求头中所有的Cookie数据数组
Response.addCookie(Cookie cookie) 发送Cookie数据到浏览器

3.3 创建Cookie

// 创建一个Cookie
Cookie cookie = new Cookie("code", "CodingMonkey");
// 设置Cookie的有效路径
cookie.setPath("/");
// 设置当前Cookie的有效时间
cookie.setMaxAge(10);
// 通过Response响应对象发送数据到浏览器
resp.addCookie(cookie);

3.4 服务器获取浏览器请求带有的Cookie的数据


// 从浏览器获取对应的Cookie 数据
@WebServlet("/getCookie")
public class GetCookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 从HttpServletRequest对象中获取浏览器请求服务器带有的Cookie数据
        Cookie[] cookies = req.getCookies();
        for (Cookie cookie : cookies) {
            // 获取Cookie的名字和Cookie的值
            System.out.println(cookie.getName() + ":" + cookie.getValue());
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

3.5 Cookie 有效的时间

Cookie cookie = new Cookie("code", "Java_Coder");
cookie.setPath("/");
/*
正数 大于0 有效时间,保存在浏览器本地磁盘中,时间Timeout自动销毁
负数 小于0 浏览器未关闭之前有效,内存存储Cookie
0 等于0 销毁Cookie
 */
cookie.setMaxAge(-1);
resp.addCookie(cookie);

3.6 Cookie的路径的问题

Cookie路径限制是为了约束当前Cookie在访问那些资源时带有对应的Cookie数据
	1. 如果是默认情况下,没有自定义约束当前Cookie数据有效路径,默认是当前项目
	2. 设置有效路径为setPath("/") 表示整个Tomcat服务器有效
	3. /Day44/admin 指定Cookie有效路径,就是URL匹配路径,在一定范围内有效,可
	以提高Cookie数据使用的安全性

4. 实现自动登录的操作

4.1 前端展示

// login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        table, tr, td, th {
            border: 1px silver solid;
        }

        table {
            width: 600px;
            margin: auto;
        }

        td {
            text-align: center;
            font-size: 32px;
        }

        input {
            font-size: 32px;
        }
    </style>
</head>
<body>
<div style="width: 100%; height: 100px; background-color: greenyellow"></div>
<hr>
<!--首先需要进行的操作是,登录个人的信息,然后实现验证操作,如果符合操作,然后进入到Servlet——Controller层中进行验证操作-->
<form action="loginServlet" method="post">
    <table>
        <tr>
            <td colspan="2">用户登陆</td>
        </tr>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username" placeholder="请输入用户名"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password" placeholder="请输入密码"></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" value="登陆"></td>
        </tr>
    </table>
</form>
</body>
</html>

4.2 Controller层

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    private static final Integer MAX_IN_ACTIVE_TIME = 60 * 60 * 24 * 15;

    /**
     * 实现核心功能的操作
     *
     * @param req 请求操作
     * @param resp 响应操作
     * @throws ServletException SQL异常抛出
     * @throws IOException IO流异常抛出
     */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
         * 首先进行编码的操作
         */
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        // 获取用户姓名、用户密码、然后进行登录操作实现
        String username = req.getParameter("username");
        String pass = req.getParameter("password");

        // 进行密码的判定操作。如果密码符合要求,验证通过。
        if ("admin".equals(username) && "root".equals(pass)){
            //登录成功的操作
            /**
             * 自动登录的实现操作
             *  1. 创建Session 对象
             *  2. Session对象存储username
             *  3. 设置Session 有效时间
             *  4. 设置和当前同步的Cookie的数据
             *  5. 设置Cookie 有效时间和Session 保持一致
             *  6. 添加Cookie 数据,同时重定向到IndexServlet
             */

            // 创建Session对象
            HttpSession session = req.getSession(true);
            // Session 对象中存储数据username
            session.setAttribute("username",username);
            // 设置Session 有效时间
            session.setMaxInactiveInterval(MAX_IN_ACTIVE_TIME);

            //设置和当前同步的cookie 的数据
            Cookie cookie = new Cookie("JSESSION", session.getId());
            // 设置有效时间和Session一致
            cookie.setMaxAge(MAX_IN_ACTIVE_TIME);

            // 添加Cookie 数据,同时重定向到IndexServlet
            resp.addCookie(cookie);

            // 登录成功之后进行重定向操作
            resp.sendRedirect("indexServlet");

        } else {
            //登录失败的操作
            resp.getWriter().append("登录失败");
            // 设置响应头信息。使用的方法是 setHeader(String name,String value)
            resp.setHeader("refresh","3;url=login.html");
        }
    }
}

@WebServlet("/indexServlet")
public class IndexServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 先解决乱码问题
        resp.setContentType("text/html;charset=utf-8");

        // 通过session 对象判断是否能够正常的登录操作
        HttpSession session = req.getSession(false);

        // 判断是否登录正常
        if (null == session || null == session.getAttribute("username")){
            resp.getWriter().append("未登录状态,请进行登录操作");

            // 设置响应头信息。使用的方法是 setHeader(String name,String value)
            resp.setHeader("refresh","3;url=login.html");
        } else {
            Object username = session.getAttribute("username");
            resp.getWriter().append("<h1>欢迎光临~~~ 尊贵的" + username + "</h1>")
                    .append("<a href='logoutServlet'>退出~~~</a>");
        }
    }
}


@WebServlet("/logoutServlet")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //创建Session对象,如果没有则不需要进行创建
        HttpSession session = req.getSession(false);

        if (session != null) {
            //销毁session对象
            session.invalidate();

            // 销毁cookie 对象
            Cookie cookie = new Cookie("JSESSION", "");
            cookie.setMaxAge(0);

            resp.addCookie(cookie);
        }
        resp.sendRedirect("login.html");
    }
}