美文网首页
对于cookie和session的总结和思考

对于cookie和session的总结和思考

作者: moutory | 来源:发表于2021-03-22 16:29 被阅读0次

前言

在JavaWeb中,由于http的无状态特性而延伸了cookie和session等工具,为我们保存客户端信息所使用。熟练地掌握cookie和session的特性和使用方法,对于Web开发人员来说,也是十分有必要的。本篇文章将对cookie和session的使用和注意事项进行介绍,希望对各位读者有所帮助。

一、Cookie篇

(一)Cookie简介
先说说Cookie产生的背景

我们知道,Http协议是无状态的,所谓无状态,是指对于服务器端而言,它并不能感知到当前发起请求的客户端和之前发起请求的客户端是否是同一个用户。也就是说,同一个客户端向服务器发起1次请求和100次请求,对于服务器而言,都是没有区别的,服务器只会根据你的请求返回相关的web资源和数据而已。
那么,如果我们需要服务器记得某个用户之前访问过服务器呢?比如说在线上商城进行购物,如果要求用户每次添加商品到购物车上都需要用户输入密码,那会给用户带来很大的不便。出于用户标识的背景需要,cookie产生了。

接着说什么是Cookie?

Cookie是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。简单来说,cookie就是存放在客户端上的一小份数据,上面存放着服务器定义好的用户标识以及其他数据,用户每次发起请求时,都会将cookie一起提交上去(如果有cookie的话)。

(二)Cookie的使用

下面我们就使用cookie来做一个简单的记录上一次登录时间案例

public class CookieServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("UTF-8");
        resp.setHeader("Content-type", "text/html;charset=UTF-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if("admin".equals(username)&&"admin".equals(password)){
            // 判断是否第一次登陆
            cookieCheck(req,resp);
        }else{
            resp.getWriter().println("账号或密码错误");
        }
    }

    private void cookieCheck(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        Cookie cookie = new Cookie("isLogged",System.currentTimeMillis()+ "");
        resp.addCookie(cookie);
        Cookie[] cookies = req.getCookies();
        for (int i =0;i<cookies.length;i++){
            if("isLogged".equals(cookies[i].getName())){
                resp.getWriter().write("您上次登陆的时间是:" + new Date(Long.parseLong(cookies[i].getValue())));
                return;
            }
        }
        resp.getWriter().write("您是第一次登陆...");
    }
}

我们可以在浏览器上面查看我们提交上去的cookie和客户端返回的cookie

在浏览器上查看我们的cookie
cookie的持久化

上面的方式虽然实现了最开始的要求,但是却有一个弊端,此时的cookie是会话cookie,也就是说一旦关闭浏览器,那么就默认会话结束,下次用户再打开浏览器访问的时候,还是会属于第一次登陆。
解决这个问题就需要对cookie进行持久化操作,我们只需要对之前的代码做出新增cookie的存在时长即可。

Cookie cookie = new Cookie("isLogged",System.currentTimeMillis()+ "");
// 有效期设置为一个小时
cookie.setMaxAge(60*60);
resp.addCookie(cookie);
cookie的删除

cookie并没有提供delete或者remove的方法,我们一般是采用将指定的cookie有效期设为0的方式来删除cookie。

// 删除cookie
private void cookieDelete(HttpServletRequest req, HttpServletResponse resp) {
    Cookie cookie = new Cookie("isLogged", null);
    cookie.setMaxAge(0);
    resp.addCookie(cookie);
 }
(三)Cookie的缺点
1. Cookie的不安全性

我们通过上文知道,cookie是存放在客户端中的,在与服务器通信的过程中有可能会遭遇cookie劫持,使得cookie的内容被恶意的第三方所获取。所以如果我们将用户的登录信息存放cookie中,一旦cookie被劫持那么用户的信息就可能会发生泄漏,还会出现劫持者无需账号密码即可登录用户账户的情况发生。
如果将cookie设为http only可以避免上述的情况发生

2. Cookie的容量

cookie文本的大小(一般为4kb),cookie的数量(一般每个站点20个)存在一些限制,每个站点只能容纳20个cookie。Cookie仅限于简单的字符串信息,他们无法存储复杂的信息。

二、Session篇

Session和Cookie一样,也是在HTTP的无状态特性下产生的,和后者不同,session最大的特点是它是存储在客户端上的数据,这样就可以在很大程度上避免cookie存放在客户端上引起的泄漏风险。接下来我们先来了解一下session的使用吧。

(一)Session的使用

我们将在servlet1中存储keynamevalue张三的值到session中,然后在servlet2从session中读取这个key。

web.xml配置
<!-- SessionServlet -->
    <servlet>
        <servlet-name>SessionServlet1</servlet-name>
        <servlet-class>com.xiaoming.web.SessionServlet1</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionServlet1</servlet-name>
        <url-pattern>/servlet1</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>SessionServlet2</servlet-name>
        <servlet-class>com.xiaoming.web.SessionServlet2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionServlet2</servlet-name>
        <url-pattern>/servlet2</url-pattern>
    </servlet-mapping>
servlet1代码
public class SessionServlet1 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        session.setAttribute("name","张三");
    }
}
servlet2代码
public class SessionServlet2 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        HttpSession session = req.getSession();
        Object name = session.getAttribute("name");
        resp.getWriter().write("name is " + name);
    }
}

我们可以在下面的结果图中看到,servlet2成功的拿到了servlet1存储在session中的value。

session演示用例

session的使用并不复杂,但如果用户的状态信息存储在session中,而session又是存储在服务端上,那么问题来了:
客户端每次请求应该怎么样才能让服务端知道哪个session是属于当前发起请求的客户呢?
答案是sessionId,服务端会将每个session的Id放在response中返回给客户端,后续每次客户端发起请求时,请求中都会携带sessionId,使得服务端可以识别当前发起请求的用户。

session作用流程图
session的存储位置、存活时间和持久化
存储位置和存活时间

session默认是存储在服务器的内存当中的,关掉浏览器并不会关闭sessionsession销毁只能通过invalidate或超时。默认情况下,session的存活时间是30min。
说到这里,可能有些人会有疑问,,如果说session的存活时间有30min,那为什么每次关掉浏览器后再访问网站,有时候有需要重新输入密码呢?
答案是,服务器是根据sessionId来识别用户的,而sessionid是存储在客户端(也就是浏览器)的内存中,一旦关闭浏览器,内存中的sessionid自然就消失了。这时,虽然服务器上面还有原来sessionid存储的值,但客户端再次发起请求时,用的已经是新的sessionid了。
同时,即使我们没有关闭浏览器,在一段时间没有操作后,session也还是会过期。我们可以通过修改配置来改变过期时间。具体可以参考这篇文章
session超时设置
需要注意的是,如果想要用户关闭浏览器后session还有效,还需要设置cookie的有效期!!!使得用户下次访问时cookie还能将原有的sessionid重新提交。

session的持久化

Session的持久化是由Session Manager来管理的,Tomcat提供了两个实现类:
org.apache.catalina.session.StandarManager
org.apache.catalina.session.PersistentManager
1、StandarManager是默认的Session Manager。它的实现机制是:当Tomcat服务器关闭或重启,或Web应用被重新加载时,会将内存中所有的HttpSession对象保存到文件系统中,默认的文件路径是:%CATALINA_HOME%\work\Catalina<applicaton-name>\SESSIONS.ser
重启Tomcat后,Tomcat服务器把SESSIONS.ser中的持久化HttpSession对象加载到内存中。
2、PersistentManager能够把HttpSession对象保存到Session Store中,它提供了比较StandarManager更灵活的管理功能,具有容错能力,控制内存中HttpSession对象的数目等

(二)Session的缺点

1、Session虽然保障了用户数据的安全,但由于存储在服务器的内存中,如果对于用户在线人数较多的网站,服务器的内存压力会比较大。
2、Session变量和cookies是同一类型的。如果某用户将浏览器设置为不兼容任何cookie,那么该用户就无法使用这个Session变量!

3、拓展性差,需要解决集群环境下session共享问题
(三)用户禁止cookie的解决方法

在pc端中,部分用户会禁止cookie的存储,这时我们就不可以直接使用cookie和session来标识用户了。我们一般会使用重写URL的方法来解决。
例如:在一个超链接中,本来要访问的URL是:

<a href="GetDataFromSession">

重写后:

<a href="GetDataFromSession;jsessionid=5480EF9016295A73DC56731A2F123246">

本质上来说,我们是将所需要的参数jsessionid,从cookie中存放改为拼接在请求的url上而已。

(四)session共享问题的解决思路
  • session sticky:就是让用户一直访问同一个服务器,俗话说就是黏在一起。但是对应的服务器也会有挂掉的时候,所以不管用
  • session复制,就是让不同服务器都有相同session,从一个服务器复制到其他服务器
  • 把session集中存储到一个地方,所有服务器都来访问此机器。但是此机器也会有挂掉的时候

三、对比篇

现如今的项目开发中,使用的工具已经不局限于session和cookie了,在前后端项目中我们更多的会使用token(一般存储在用户浏览器中的sessionStoragelocalStorage),从而减轻服务器的压力。相关的对比图如下:

session、cookie等存储方式对比图

小结

本篇文章从cookie和session的作用入手开始介绍,这两者的作用都是用于标识用户以及存储用户数据的工具,二者最大的区别在于用户标识存储的位置,在了解其基本用法的基础上,我们知道了关闭浏览器后session失效的背后原因和解决方案如何解决用户禁用cookie的场景,以及cookie和session面对集群的常见处理方式。同时文章也介绍了cookie、session、localStorage、sessionStorage这几种存储方式的区别。
本篇文章对于token的使用方式介绍较少,有兴趣的同学可以自行百度研究或者参考下面的参考文章。同时文章中对于session解决集群的具体实现方案没有阐述,大家也可以自行了解。

参考文章:
Session存放在什么位置(Session持久化):
https://www.soosmart.com/topic/592.html
URL 重写:
https://blog.csdn.net/qq_42857603/article/details/82897870
开发中经常碰到的问题cookie和session问题,今天一并解决:
https://cloud.tencent.com/developer/article/1345905
cookies、sessionStorage和localStorage解释及区别:
https://www.cnblogs.com/pengc/p/8714475.html
存储方式详解(cookie、session、Token):
https://blog.csdn.net/CEO___/article/details/103326248

相关文章

网友评论

      本文标题:对于cookie和session的总结和思考

      本文链接:https://www.haomeiwen.com/subject/rvdgcltx.html