Cookie和Session

本文详细介绍了Web开发中用于会话管理的Cookie和Session。Cookie是存储在用户本地的小型文本文件,用于辨别用户身份和跟踪Session。Session则将用户信息存储在服务器端,更安全但消耗更多服务器资源。Cookie可通过Expires、Path、Domain、Secure和HTTPOnly属性进行配置。Session通过SessionID在服务器端管理,其生命周期和超时机制也进行了阐述。同时,讨论了在不同场景下如何选择使用Cookie和Session。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Cookie

Cookie,有时也用其复数形式 Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。

Cookie 并不是它的原意“甜饼”的意思, 而是一个保存在客户机中的简单的文本文件, 这个文件与特定的 Web 文档关联在一起, 保存了该客户机访问这个Web 文档时的信息, 当客户机再次访问这个 Web 文档时这些信息可供该文档使用。由于“Cookie”具有可以保存在客户机上的神奇特性, 因此它可以帮助我们实现记录用户个人信息的功能, 而这一切都不必使用复杂的CGI等程序 。

举例来说, 一个 Web 站点可能会为每一个访问者产生一个唯一的ID, 然后以 Cookie 文件的形式保存在每个用户的机器上。如果使用浏览器访问 Web, 会看到所有保存在硬盘上的 Cookie。在这个文件夹里每一个文件都是一个由“名/值”对组成的文本文件,另外还有一个文件保存有所有对应的 Web 站点的信息。在这里的每个 Cookie 文件都是一个简单而又普通的文本文件。透过文件名, 就可以看到是哪个 Web 站点在机器上放置了Cookie(当然站点信息在文件里也有保存) 。

Cookie组成

Cookie是一段不超过4KB的小型文本数据,由一个名称(Name)、一个值(Value)和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。其中 :

(1)Name/Value:设置Cookie的名称及相对应的值,对于认证Cookie,Value值包括Web服务器所提供的访问令牌 。

(2)Expires属性:设置Cookie的生存期。有两种存储类型的Cookie:会话性与持久性。Expires属性缺省时,为会话性Cookie,仅保存在客户端内存中,并在用户关闭浏览器时失效;持久性Cookie会保存在用户的硬盘中,直至生存期到或用户直接在网页中单击“注销”等按钮结束会话时才会失效 。

(3)Path属性:定义了Web站点上可以访问该Cookie的目录 。

(4)Domain属性:指定了可以访问该 Cookie 的 Web 站点或域。Cookie 机制并未遵循严格的同源策略,允许一个子域可以设置或获取其父域的 Cookie。当需要实现单点登录方案时,Cookie 的上述特性非常有用,然而也增加了 Cookie受攻击的危险,比如攻击者可以借此发动会话定置攻击。因而,浏览器禁止在 Domain 属性中设置.org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,以减小攻击发生的范围 。

(5)Secure属性:指定是否使用HTTPS安全协议发送Cookie。使用HTTPS安全协议,可以保护Cookie在浏览器和Web服务器间的传输过程中不被窃取和篡改。该方法也可用于Web站点的身份鉴别,即在HTTPS的连接建立阶段,浏览器会检查Web网站的SSL证书的有效性。但是基于兼容性的原因(比如有些网站使用自签署的证书)在检测到SSL证书无效时,浏览器并不会立即终止用户的连接请求,而是显示安全风险信息,用户仍可以选择继续访问该站点。由于许多用户缺乏安全意识,因而仍可能连接到Pharming攻击所伪造的网站 。

(6)HTTPOnly 属性 :用于防止客户端脚本通过document.cookie属性访问Cookie,有助于保护Cookie不被跨站脚本攻击窃取或篡改。但是,HTTPOnly的应用仍存在局限性,一些浏览器可以阻止客户端脚本对Cookie的读操作,但允许写操作;此外大多数浏览器仍允许通过XMLHTTP对象读取HTTP响应中的Set-Cookie头。

写入与读取

Cookies集合是附属于Response对象Request对象的数据集合,使用时需要在前面加上Response或Request。用于给客户机发送Cookies的语法通常为:

< %Response.cookies(“Cookies名称”)=数据% > 

当给不存在的Cookies集合设置时,就会在客户机创建,如果该Cookies己存在,则会被代替。由于Cookies 是作为HTTP传输的头信息的一部分发给客户机的,所以向客户机发送Cookies的代码一般放在发送给浏览器的HTML 文件的标记之前。如果用户要读取Cookies,则必须使用Request对象的Cookies集合,其使用方法是:

< %efg=request.cookies(“abc”) (将cookies对象abc的值赋给efg)% > 

需要注意的是,只有在服务器未被下载任何数据给浏览器前,浏览器才能与Server进行Cookies集合的数据交换,一旦浏览器开始接收Server所下载的数据,Cookies的数据交换则停止,为了避免错误,要在程序和前面加上response.Buffer=True。

生成Cookie

        //创建两个cookie
        Cookie cookie = new Cookie("school", "school_1");
        Cookie cookie1 = new Cookie("teacher", "teacher_1");
        //指定cookie绑定路径,如果不绑定,默认为当前路径下的所有同类请求
        //注意,这里指定的路径要求必须要添加项目名称
        cookie.setPath(req.getContextPath() + "/aaa/xxx/ooo");
        cookie1.setPath(req.getContextPath() + "/bbb");
        //设置cookie的有效期,整型,单位为秒
        //该值大于0 ,表示将cookie存放到客户端的硬盘
        //该值小于0,与不设置效果相同,会将cookie存放到浏览器缓存
        //该值等于0,表示cookie一生成,马上消失
        cookie.setMaxAge(60);
        //设置cookie有效时间为10天
        cookie1.setMaxAge(60*60*24*10);
        //向响应中添加cookie
        resp.addCookie(cookie);
        resp.addCookie(cookie1);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zwXOLJAy-1629193412606)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210802163339308.png)]

注意:如果不设置setMaxAge()则在会话结束时cookie失效

获取客户端cookie

//获取请求中的cookie
Cookie[] cookies = req.getCookies();
if (cookies != null) {
    for (Cookie cookie : cookies) {
        System.out.println(cookie.getName() + "===" + cookie.getValue());
    }
}else {
    System.out.println("未存在任何cookie");
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CEbpLsqe-1629193412610)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210802165115024.png)]

注意:Cookie不要轻易禁用

ServletContext、HttpSession、HttpServletRequest三个域属性空间比较

ServletContext:即application,置入其中的域属性是整个应用范围的,可以完成垮回话共享数据

HttpSession:置入其中的域属性时会话范围的,可以完成垮请求共享数据

HttpServletRequest:置入其中的域属性时请求范围的,可以完成垮servlet共享数据,但这些servlet必须在同一请求中

对于这三个域属性空间对象的使用原则是,在可以保证功能需求的前提下,优先使用小范围的,这样不仅可以节省服务器内存,还可以保证数据的安全性。

Session

session,即会话,是web开发中的一种会话状态跟踪技术。前面的cookie也是一种会话跟踪及时。不同的是cookie是将会话状态保存在了客户端,而session则是将会话状态保存在了服务器端。

那么到底什么是“会话”?当用户打开浏览器,从发出第一次请求开始,一直到最终关闭浏览器,就表示一次会话完成。

session并不是javaweb开发所特有的,而是整个web开发中所使用的技术,在javaweb开发中,session是以javax.servlet.http.HttpSession的接口对象形式出现的。

对Session域属性空间的操作

Session是一个专门用于存放数据的集合,我们一般称这个用于存放数据的内存空间为域属性空间,简称域。HttpSession中具体有三个方法,是专门用于对该域属性空间中数据进行写、读操作的。

public void setAttribute(String name,Object value)

该方法用于向Session的域属性空间中放入指定名称、指定值的域属性

public Object getAttribute(String name)

该方法用于从session的域属性空间中读取指定名称为域属性值

public void removeAttribute(String name)

该方法用于从Session的域属性空间中删除指定名称的域属性

    @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 password = req.getParameter("password");
        //将参数放入request域
        req.setAttribute("user",username);

        //获取 Session对象
        HttpSession session = req.getSession();
        //向Session域中写入属性
        session.setAttribute("user_name",username);
        resp.getWriter().print("SessionServlet:" + username);
    }

获取session:

public class SessionServlet02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String user_name = null;
        //从request域中读取user属性
        String user = req.getParameter("user");
        resp.getWriter().println("SessionServlet02:" + user);
        //重session域中读取数据
        //获取session
        HttpSession session = req.getSession(false);
        if (session != null) {
            user_name = (String) session.getAttribute("user_name");
        }

        resp.getWriter().println("SessionServlet02:" + user_name);
    }
}
<form action="session" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="提交">
</form>

使用zhangsan 登陆:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LOaKVaMl-1629193412612)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210802174730869.png)]

再访问session02:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PbrE68xQ-1629193412615)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210802174821665.png)]

可以看到requset域不能在不同请求中访问,而session域可以用getAttribute()获取session队形。

getSession(true) 和 getSession()相等,即有这个session就用原本的session,没有则创建

getSession(flase)表示有session则用原来session,没有,则返回null,读取数据只有从老的session才有可能存在要查找的数据,新建的session中不可能有这些数据。

Session的工作原理

在服务器中系统会为每个会话维护一个Session。不同的会话,对应不同的Session。一个会话会一直找一个session。

1、写入Session列表

服务器 对当前应用中的Session是以Map的形式进行管理的,这个Map称为Session列表。该Map的key为一个32位长度的随机串,这个随机串称为JSessionID,value则为Session对象的引用。

当用户第一次提交请求时,服务器端Servlet中执行到request.getSession()方法后,会自动生成一个Map.Entry对象,key为一个根据某种算法新生成的JSessionID,value则为新创建的HttpSession对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cYkbzUFl-1629193412618)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210802193410080.png)]

2、服务器生成并发送Cookie

在将Session信息写入Session列表后,系统还自动将“JSessionID"作为name,这个32位长度的随机串作为value,以Cookie的形式存放到响应头中,并随着响应,将该Cookie发送到客户端。

3、客户端接收并发送Cookie

客户端接收到这个Cookie后会将其存放到浏览器的缓存中,即只要客户端浏览器不关闭,浏览器缓存中的Cookie就不会消失。当用户第二次提交请求时,会将缓存中的这个Cookie,伴随着请求的头部信息,一块发送到服务端。

4、从Session列表中查找

服务端从请求中读取到客户端发送来的Cookie,并根据Cookie的JSessionID的值,总Map中查找相应key所对应的value,即Session对象。然后,对该Session对象的域属性进行读写操作。

Session失效

web开发中引入了Session超时的概念,Session的失效就是指Session的超时。若某个Session在指定的时间范围内一直未被访问,那么Session将超时,即将失效。

在web.xml中可以通过<session-config/> 标签设置Session的超时时间,单位为分钟。默认Session的超时时间为30分钟。需要再次强调的是,这个时间并不是从Session被创建开始计时的生命周期时长,而是从最后一次被访问开始计时,在指定的时间内一直未被访问的时长。

<!-- 设置Session的失效时间 -->
<session-config>
	<session-timeout>120</session-timeout>
</session-config>

若未到时间时限,也可通过代码提前是Session失效。HttpSession中的方法invalidate(),使得Session失效,但session并不为null。

public void invalidate()

如果浏览器禁用cookie则每次请求服务器都会创建一个session给浏览器。但如果在请求中加 ;jsessionid = 32位jsessionid码 则还是可以使用之前发送过来的session,并且是同一个session,这样就又实现了会话跟踪。

String uri = req.getContextPath()+"/otherServlet";//解决禁用cookie后Session的重定向传递跟踪问题。uri = resp.encodeRedirectURL(uri);resp.sendRedirect(uri);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p7NTObku-1629193412619)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210802204012428.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值