Cookie 和 Session 的那点事!
❝HTTP是无状态的协议。无状态就是指当一个浏览器客户程序于服务器之间多次进行基于HTTP请求/响应模式的通信时,HTTP协议本身没有提供服务器连续跟踪特定浏览器端状态的规范。(由无状态,从而引入cookie和session等,老规矩有时间再写,已经欠下不少篇了。) ❞
我曾在HTTP文章中立下过这个flag,现在这篇就是来兑现的!温情提示,本文使用的测试浏览器为Firefox 83.0(64位)。
HTTP是无状态的
既然这篇是在讲Cookie和Session,那么就不得不提到HTTP是无状态的这一特性,下面说一下无状态具体的特点:
- 协议对于事务处理没有记忆能力。
- 对同一个url请求没有上下文关系。
- 每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况。
- 服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器。
关于HTTP是无状态的,更通俗的理解是,服务端是不记忆客户端的,当客户端的一次请求结束后,服务端就会忘记它,尽管它后来可能会频繁的访问该服务端,客户端都会认为每次是新的请求访问,当服务端不需要先前的信息时它的应答就会比较快,可是如果后续请求需要先前信息时,就会导致每次请求访问都会有大量重复的信息内容。而且随着网络技术的发展,我们越发希望服务器端可以记住我们的状态的让我们使用更加快捷方便,比如记住密码,自动登录,网上购物,这时Cookie和Session应运而生。
Cookie
1.什么是Cookie?
Cookie的中文是“饼干、甜点”的意思,由客户端拿着送到服务器的,有没有点送礼的味道? 我们前面说过,Cookie是为了实现HTTP的“有状态”而存在的,所谓的“有状态”可以理解为服务端可以判断用户身份和状态。Cookie其实就是Key/Value键值对,当用户端向服务端发起请求后,服务端记录该用户状态,并返回给客户端一个Cookie,然后客户端就会在本地保存这个Cookie。
前面用送礼来打比方,其实不算太恰当,我们换个比喻,现在小区大多都安装了电子门禁,我们需要刷门禁卡才能进去,当你办理门禁卡后,这个门禁卡存放着你的一些信息,你只要刷卡就能进入。Cookie就相当于门禁卡,你拿着门禁卡,就能证明你是这个小区的住户,你就可以进入这个小区。
「Cookie的主要功能:」 购物车、登录状态等、个性化设置等。
2. Cookie的属性
Cookie有Version 0 和 Version 1两个版本,后者确实比较新,但是接受度并不广,尽管Servlet 3.0规范中创建的Cookie即支持Version 0也支持Version 1,但是Java Web的Serlet规范中不支持Set-Cookie2响应头(不过只要其属性符合RFC规范,都是可以在Set-Cookie响应头下兼容的)。
Name/Value | 键值对,设置Cookie的名称及相对应的值,对于认证Cookie,Value值包括Web服务器所提供的访问令牌。 |
---|---|
Expires | 设置Cookie的有效期。 |
Domain | 指定了可以访问该 Cookie 的 Web 站点或域,domain = "xxx.net"。 |
Path | 指定该Cookie是在当前哪个路径下生成的,path=/xxx/。 |
Secure | 指定是否使用HTTPS安全协议发送Cookie。 |
3. Cookie的运行流程
代码语言:javascript复制@GetMapping("/CookieAdd")
public String Cookie_Test(HttpSession session , HttpServletRequest request, HttpServletResponse response){
Cookie cookie = new Cookie("zzxkj","hello"); //设置cookie
cookie.setMaxAge(60); //设置cookie生存时间,默认为-1,即只在会话中存在
response.addCookie(cookie);
return "这里是增加Cookie的界面";
}
@GetMapping("/CookieTest")
public String Cookie_Add(HttpSession session , HttpServletRequest request, HttpServletResponse response){
Cookie[] cookies = request.getCookies();
String result = "不存在cookie";
if (cookies!=null){
for (Cookie cookie:cookies) {
if (cookie.getName().equals("zzxkj")){
result = cookie.getValue();
}
}
}
return result;
}
- 首次访问http://localhost:8080/CookieAdd,增加Cookie("zzxkj","hello"),我们发现Cookie是完全暴露的,而且第一次请求访问时,是不带有该cookie的,因为根本就还没有存~
- 再次访问http://localhost:8080/CookieTest,发现请求中已经携带了Cookie("zzxkj","hello")
- 等待60s后,再次访问http://localhost:8080/CookieTest,发现请求中的Cookie("zzxkj","hello")已经失效被销毁了
Session
1.Session是什么?
Session的意思是会话,指的是在一段时间内,单个客户与Web应用的一连串相关的交互过程。前面讲述的cookie使HTTP“有状态”的原理是,在客户端本地存放数据,并且在每次请求时都带上这些数据,这就会导致大量的数据被重复发送,而session正好克服了这个问题。
2.Session的属性
SessionID | 获取Session编号,一般在会话开始的时候由服务器自动分配一个标识SessionId,整个会话过程中的SessionId保持不变 |
---|---|
TimeOut | 设置Session对象的超期时间,默认为20分钟 |
Keys | 根据索引号获取Session变量值 |
Count | 获取Session变量的总数量 |
3.Session的运作流程
代码语言:javascript复制@GetMapping("/SessionTest")
public String Session_Test(HttpSession session , HttpServletRequest request, HttpServletResponse response){
String result = (String) session.getAttribute("zzxkj");
String url = request.getRequestURL().toString();
System.out.println(url);
return result;
}
@GetMapping("/SessionAdd")
public String Session_Add(HttpSession session , HttpServletRequest request, HttpServletResponse response){
session.setAttribute("zzxkj","hello");
return "这里是增加Session的界面";
}
- 首次访问http://localhost:8080/SessionAdd,或者该web应用中任意一个支持会话的网页,Servlet容器会创建一个HttpSession对象,并为它分配唯一的SessionID,并新建一个Cookie("JSESSIONID","8E5551E0590B30C39504A8FAC6459B5C")添加到HTTP response中发送给客户端。
- 再次访问http://localhost:8080/SessionAdd,或者该web应用任意一个支持会话的网页,在客户端的request中,会带着名为JSESSION的Cookie("JSESSIONID","8E5551E0590B30C39504A8FAC6459B5C")发送给服务端,Servlet容器就会寻找表示SessionID的Cookie,找到则表示当前请求是在一个会话中。
- 会话被销毁,HttpSession对象结束生命周期
cookie和session的灵魂拷问-》
Cookie和Session的联系,以及禁用Cookie后Session该如何工作?
从上面讲述Session的运作流程的这一小节中,我们可以看出在「浏览器不禁用cookie的时候,Session是基于Cookie工作的」,具体的流程就是将第一次访问时,服务器返回的JSESSION存放在客户端cookie中,且该cookie的expires值为-1,也就是说该cookie在会话结束后将被销毁。那么在禁用Cookie后Session该如何工作呢?答案是,通过重写URL来跟踪会话(拼接JSESSIONID),在Java中HttpServletResponse接口提供了两种重写URL的方法。
代码语言:javascript复制 response.encodeRedirectURL();
response.encodeURL();4
❝这两种方法功能上没什么区别,当客户端禁用Cookie时会重写URL,也就是将JSESSIONID拼接到原URL后,用保留符“;”隔开。只是当encodeURL()方法会对URL参数进行检查,当参数为空时,它会直接返回完整URL,也就是说endodeURL()可以被要求用来返回绝对地址,而encodeRedirectURL()则主要用来判断是否拼接JSESSIONID。 ❞
「当客户端禁用Cookie时通过重写URL来跟踪会话:」
- 设置浏览器禁用cookie,我用的是火狐浏览器83.0,若用别的浏览器请自行百度禁用Cookie方法;
- 使用encodeRedirectURL方法重写"/SessionTest",response.encodeRedirectURL("/SessionTest");
- 使用新的URL地址:localhost:8080/SessionAdd;jsessionid=6DDA3DDBC9FA646EAE7C9A1F89105CD1,来发送访问请求。
SessionID(JSESSIONID)是如何产生的?
在一次会话开始时,Servlet容器将会通过调用HttpServletRequest对象的getSession()方法创建一个HttpSession对象,同时生成一个与之相对应的SessionID标识符,而且会将这个session对象添加到org.apache.catalina.Manager类的session容器中保存。tomcat的Manager类提供创建SessionID的方法:随机数 时间 jvmid;
cookie和session的区别?
- 「存储容量不同:」session大小取决于内存,所以也可以认为大小没有限制;单个cookie保存的数据长度大多不能超过4k(Chrome可以大于80000个字节),每个域名大约可以保存50个(IE6限制20个)
- 「存取方式不同:」session可以存放任意的数据类型,String、Map、List等; cookie只能存放ASSIC字符,这些特殊字符:“空格,方括号,圆括号,等于号(=),逗号,双引号,斜杠,问号,@符号,冒号,分号”不能被使用,如需设置则可以通过response.encodeURL()对其编码,否则将抛出IllegalArgumentException异常。使用中文时,将自动转码。如下,打印cookie内容(你好),以及cookie版本号。
- 「存储位置不同:」session存放在服务端,多用户容易加大服务器的负担;cookie存放在客户端,且明文暴露,不安全;
- 「有效期不同:」session默认会话结束或者超时就会被销毁,而且如果设置session超时时间过长,会使服务器累计Session过多,导致内存泄漏;cookie可以设置为较长时间存放。
Continue
Waiting......Token_JWT?