❝HTTP是无状态的协议。无状态就是指当一个浏览器客户程序于服务器之间多次进行基于HTTP请求/响应模式的通信时,HTTP协议本身没有提供服务器连续跟踪特定浏览器端状态的规范。(由无状态,从而引入cookie和session等,老规矩有时间再写,已经欠下不少篇了。) ❞
我曾在HTTP文章中立下过这个flag,现在这篇就是来兑现的!温情提示,本文使用的测试浏览器为Firefox 83.0(64位)。
既然这篇是在讲Cookie和Session,那么就不得不提到HTTP是无状态的这一特性,下面说一下无状态具体的特点:
关于HTTP是无状态的,更通俗的理解是,服务端是不记忆客户端的,当客户端的一次请求结束后,服务端就会忘记它,尽管它后来可能会频繁的访问该服务端,客户端都会认为每次是新的请求访问,当服务端不需要先前的信息时它的应答就会比较快,可是如果后续请求需要先前信息时,就会导致每次请求访问都会有大量重复的信息内容。而且随着网络技术的发展,我们越发希望服务器端可以记住我们的状态的让我们使用更加快捷方便,比如记住密码,自动登录,网上购物,这时Cookie和Session应运而生。
Cookie的中文是“饼干、甜点”的意思,由客户端拿着送到服务器的,有没有点送礼的味道? 我们前面说过,Cookie是为了实现HTTP的“有状态”而存在的,所谓的“有状态”可以理解为服务端可以判断用户身份和状态。Cookie其实就是Key/Value键值对,当用户端向服务端发起请求后,服务端记录该用户状态,并返回给客户端一个Cookie,然后客户端就会在本地保存这个Cookie。
前面用送礼来打比方,其实不算太恰当,我们换个比喻,现在小区大多都安装了电子门禁,我们需要刷门禁卡才能进去,当你办理门禁卡后,这个门禁卡存放着你的一些信息,你只要刷卡就能进入。Cookie就相当于门禁卡,你拿着门禁卡,就能证明你是这个小区的住户,你就可以进入这个小区。
「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。 |
@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;
}
Session的意思是会话,指的是在一段时间内,单个客户与Web应用的一连串相关的交互过程。前面讲述的cookie使HTTP“有状态”的原理是,在客户端本地存放数据,并且在每次请求时都带上这些数据,这就会导致大量的数据被重复发送,而session正好克服了这个问题。
SessionID | 获取Session编号,一般在会话开始的时候由服务器自动分配一个标识SessionId,整个会话过程中的SessionId保持不变 |
---|---|
TimeOut | 设置Session对象的超期时间,默认为20分钟 |
Keys | 根据索引号获取Session变量值 |
Count | 获取Session变量的总数量 |
@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的界面";
}
从上面讲述Session的运作流程的这一小节中,我们可以看出在「浏览器不禁用cookie的时候,Session是基于Cookie工作的」,具体的流程就是将第一次访问时,服务器返回的JSESSION存放在客户端cookie中,且该cookie的expires值为-1,也就是说该cookie在会话结束后将被销毁。那么在禁用Cookie后Session该如何工作呢?答案是,通过重写URL来跟踪会话(拼接JSESSIONID),在Java中HttpServletResponse接口提供了两种重写URL的方法。
response.encodeRedirectURL();
response.encodeURL();4
❝这两种方法功能上没什么区别,当客户端禁用Cookie时会重写URL,也就是将JSESSIONID拼接到原URL后,用保留符“;”隔开。只是当encodeURL()方法会对URL参数进行检查,当参数为空时,它会直接返回完整URL,也就是说endodeURL()可以被要求用来返回绝对地址,而encodeRedirectURL()则主要用来判断是否拼接JSESSIONID。 ❞
「当客户端禁用Cookie时通过重写URL来跟踪会话:」
在一次会话开始时,Servlet容器将会通过调用HttpServletRequest对象的getSession()方法创建一个HttpSession对象,同时生成一个与之相对应的SessionID标识符,而且会将这个session对象添加到org.apache.catalina.Manager类的session容器中保存。tomcat的Manager类提供创建SessionID的方法:随机数+时间+jvmid;
Continue
Waiting......Token_JWT?