菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
222
0

Cookie和Session解析

原创
05/13 14:22
阅读数 12541

1 Cookie工作原理

会话是由一组请求和响应组成,在请求和响应之间一定是需要数据传递的,即需要进行会话状态跟踪。(会话可以理解为,打开浏览器,从发出第一次请求开始,到最后关闭浏览器,为一次会话。)但是HTTP协议是一种无状态协议,在不同的请求之间无法进行数据传递和共享,也就是说,这一次请求和上一次请求是没有任何关系的,互相不认识。那么,就需要Cookie来实现不同请求之间数据传递的会话跟踪

Cookie是由服务器生成的,保存在客户端的信息载体,维系客户端和服务器之间的状态同步。HTTP最初的设计是无状态的,但是无状态的HTTP无法满足日益发展的需求,所以业界扩展了HTTP协议,增加了有状态的协议头,使之变成有状态协议。而这个有状态的协议头,就是靠Cookie实现的

当用户在提交第一次请求时,由服务器生成Cookie,并将其封装到响应头中,以响应的形式发送给客户端。客户端收到这个响应后,将Cookie保存到客户端。当客户端再次发送同类请求,在请求中会携带保存在客户端的Cookie数据,发送到服务端,由服务器对会话进行跟踪

2 Cookie作用范围

2.1 默认情况

默认情况下,Cookie只有在同类请求下才有效。所谓同类请求,就是指资源路径相同的请求。只有资源路径相同的请求,才会带上Cookie

比如,以下服务器代码会设置一个Cookie

@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping("/test")
    public String hello(HttpServletResponse response) {
        Cookie cookie = new Cookie("test", "hello");
        response.addCookie(cookie);
        return "success";
    }
}

那么,在第一次访问localhost:8080/hello/test这个路径的时候,我们可以看到

设置Cookie

在响应头中有Set-Cookie项,并且Cookie里面保存的键是test,值是hello

当我们访问localhost:8080/hello/test1这个路径的时候,虽然会返回404,但是我们在请求头中可以看到存在Cookie

带Cookie的请求

说明,这次请求是带了上次返回来保存的Cookie的

但是,当我们访问localhost:8080或者localhost:8080/test等其他不是localhost:8080/hello下的资源路径,在请求头中不存在Cookie

不带Cookie的请求

说明,这次请求不带Cookie

以上是默认情况下,同一个Cookie的作用范围,也就是在同类请求才会带上Cookie

2.2 设置Cookie作用路径

我们可以手动设置Cookie的作用路径

比如

@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping("/test")
    public String hello(HttpServletResponse response) {
        Cookie cookie = new Cookie("test", "hello");
        cookie.setPath(request.getContextPath() + "/abc");
        response.addCookie(cookie);
        return "success";
    }
}

我们关闭之前的浏览器,重新打开(或者直接清除之前保存的Cookie),访问localhost:8080/hello/test,可以看到

set Cookie

同样在响应头中返回了一个Set-Cookie,但是在里面还附加了一个Path,指定了此Cookie的作用范围

当我们访问localhost:8080/hello/test1时,在请求头中看到,没有Cookie项

request with no Cookie

但是,但我们访问localhost:8080/abc或者/abc路径下的资源时,在请求头中存在Cookie项

requst with Cookie

以上便是手动指定Cookie的作用范围

3 Cookie生命周期

默认情况下,Cookie的生命周期为浏览器会话期间,Cookie保存在浏览器缓存中,只要关闭浏览器,Cookie就会消失

但是,可以手动设置Cookie的有效时间。此时,Cookie会被保存在硬盘中,在有效期内,关闭浏览器,Cookie并不会消失

4 服务端的Cookie解析

根据上文讲的Cookie的作用范围和生命周期,我们可以编写服务端的Cookie解析

@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping("/test")
    public String hello(HttpServletRequest request, HttpServletResponse response) {
        Cookie cookie = new Cookie("test", "hello");
        response.addCookie(cookie);
        return "success";
    }

    @RequestMapping("/parse")
    public String parse(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        String res = "";
        for (Cookie cookie : cookies) {
            res += cookie.getName() + ": " + cookie.getValue();
        }
        return res;
    }
}

获取到Cookie之后,就可以利用Cookie实现一些功能

5 Session工作原理

Session,也就是会话,是Web开发中的一种会话状态跟踪技术。作用和Cookie是类似的,只是Cookie由服务端生成,保存在客户端,而Session则是保存在服务端

在服务器中会为每个会话维护一个Session,不同的会话对应不同的Session。也就是说,服务端会同时存在多个Session,以供不同的会话使用。那么为了达到不同的会话使用不同的Session,Session是配合Cookie实现的

1. 写入Session列表

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

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

2. 服务器生成并发送Cookie

在将Session的信息写入Session列表后,系统还会将"JSessionID"作为name,JSessionID的值(32位长度的随机串)作为value,以Cookie的形式存放到响应头中,发送到客户端

@RequestMapping("/test2")
public String setSession(HttpSession session) {
    session.setAttribute("hello", "world");
    return "seccess";
}

在请求这个方法后,我们可以看到

在响应头中,有一个Set-Cookie项,里面是JSessionID和对应的值

3. 客户端接收并发送Cookie

客户端接收到这个Cookie之后,会将其存放在浏览器的缓存中,也就是只要浏览器不关闭,缓存中的Cookie不会消失。当用户提交第二次请求时,会将缓存中的这个Cookie放入请求头中,发送到服务端

比如

@RequestMapping("/test3")
public String getSession(HttpSession session) {
    String param = (String) session.getAttribute("hello");
    return param;
}

当访问此代码时,可以看到

在请求头中的Cookie项中,有JSessionID,而且在后端也成功获取到了Session中"hello"对应的值"world"

4. 从Session列表中查找

服务器从请求中读取到客户端发送来的Cookie,根据Cookie的JSessionID值,从Map中获取对应的HttpSession对象的引用,然后可以对该对象的域属性进行读写操作

5 Session的生命周期

Session是有存活时间的,而Session失效就是指Session的超时,如果某个Session在指定的时间内一直未被访问,那么该Session将超时,会失效

默认的Session超时时间为30分钟,可以手动设置超时时间,也可以手动提前使Session失效(Session失效以后,对应的引用并不为空,但无法再继续使用,内部所有键值对全部解绑)

6 总结

由于HTTP协议的无状态性,为了使某个域名下的所有网页能够共享某些数据,我们可以使用Cookie和Session

Session存储在服务器,为一个Map,拥有唯一识别符号JSessionID,通过设置Cookie发送给客户端,Cookie存储在客户端中

客户端携带Cookie发送请求到服务器,服务器从Cookie中解析出JSessionID,再从Map中找到对应的Session

Cookie是实现Session的其中一种方案,也是最常用的,但不是唯一方法,禁用Cookie之后还有其他方法存储,比如放在url中

发表评论

0/200
222 点赞
0 评论
收藏