在这一篇文章当中,我们提到了什么是cookie和session。
【网络原理8】HTTP请求篇_革凡成圣211的博客-CSDN博客HTTP的常见属性,URL,User-Agent,Refer,get 和post的区别https://blog.csdn.net/weixin_56738054/article/details/129180661?spm=1001.2014.3001.5502它们分别是客户端会话技术和服务端会话技术。
分别把用户的信息保存在客户端磁盘和服务端,二者一般是相互配合使用的。
当用户访问一个网站之后,这个网站会把用户的关键信息(例如身份标识符)存储到cookie当中,也就是用户的本地磁盘当中。
当后续用户再次访问这个网站的时候,就会携带这个cookie,然后在服务器当中根据这个cookie来获取这个用户的其他信息。
一般请求下,服务器只要不重启,同一个客户请求同一个网站的情况下,用户的cookie当中的身份标识符不会改变。
下面,就来聊一下session和cookie的常见api
目录
HttpSession session=req.getSession();
第三步:编写登录的接口,并且把用户登录的信息保存在session当中
如果在其中一个浏览器登录了,可以在另外一个浏览器直接访问登录页面吗?
HttpSession session=req.getSession();
这一个方法,既可以用于获取到服务器上面的会话,又可以用于创建会话。
但是,这一个方法在HttpServletRequest当中是存在多态的。
当传入参数为true的时候:
会话存在,则获取;会话不存在,则创建。
当传入参数为false的时候:
会话存在,则获取;会话不存在,则返回null
当调用getSession()方法的时候,会做什么事情
步骤1:创建会话
首先先获取到HTTP请求头当中cookie这个属性里面的sessionId字段。
接着,判断这一个sessionId是否在当前的服务器当中存在。
如果不存在,那么就进入创建会话的逻辑。
第一步:首先创建一个HttpSession对象,并且生成一个sessionId(用16进制来表示);
第二步:把sessionId作为key,这一个session对象作为value。保存到服务器的一个类似于"哈希表"的结构当中。(这个数据是保存到内存当中的,并不是持久化的)
第三步:服务器返回一个HTTP响应,把sessionId通过Set-cookie字段返回给浏览器。
也就是返回给用户。
然后用户下次再次访问的时候,就可以通过这个cookie字段来获取了。
下面,图解一下创建会话的流程:
步骤2:获取会话
先获取到请求的cookie里面的sessionId字段。
然后判断这个sessionId是否在当前的服务器上面存在(也就是是否在这个哈希表当中存在)
如果有,那么直接返回这个sessionId对应的对象。
HttpSession对象
每一个HttpSession对象都是通过键值对的形式来存储数据的。
当存储数据的时候,需要调用session.setAttribute(k,v)的方式来存储。
key是String的类型,value是Object的类型
看上去有点绕,怎么出现了套娃呢...那就画个图来解释一下吧~:
一个服务器当中可以有多个session对象,每一个session对象都拥有一个sessionId。
每一个session对象都对应多个键值对
setAttribute()和getAttribute()
这两个方法,左边的那个是拥有设置key-value的。右边那个是通过key来获取value的。
当调用setAttribute之后,就相当于往已经创建的session对象当中存放key和value。
session设置最大时间
session.setMaxInactiveInterval()这个方法可以设置当前session对象的存活时间
Cookie[] getCookies方法
通过调用req.getCookies方法,可以获取到用户提交的HTTP请求头当中的cookie字段对应哪些键值对:代码实现
@WebServlet("/servlet4")
public class Servlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies= req.getCookies();
for(int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
System.out.println(cookie.getName()+"...."+cookie.getValue());
}
}
}
运行结果:
使用Fidller抓包:
可以看到,此时服务器就获取到了两个cookie对象。
resp.addCookie()方法
此处传入的是一个Cookie类型的数据,Cookie也是由键值对组成的结构。键和值都是String类型的数据。
Cookie cookie=new Cookie("hello","hi");
Cookie cookie1=new Cookie("hello","hi");
resp.addCookie(cookie);
resp.addCookie(cookie1);
这个addCookie方法,其实就相当于给客户端浏览器发送一个cookie类型的键值对。
然后,可以在HTTP响应报头的set-cookie字段当中看到这一个字段。
下面,通过一个网页登录的案例来体会一下cookie和session。
实现登录-跳转页面的案例
第一步:约定登录前后端交互的格式
登录接口的请求方式:
协议版本:HTTP/1.1
请求方法:POST;
请求路径:/Servlet;
接收方式(Content-type):application/x-www.form-urlencoded
(也就是userName="***"&password="***")这样的格式
登录接口的响应方式:
响应行:HTTP/1.1 302(需要重定向);
重定向:Location: index。(重定向到index这个路径)
第二步:约定如何获取主页的交互
获取主页的请求方式:
HTTP版本:HTTP/1.1
请求方法:GET;
请求路径:/index;
没有参数需要提交
响应的格式:
HTTP版本:1.1;
状态码:200;
响应格式:Content-Type: text/html(返回一个html页面)
第三步:编写登录的接口,并且把用户登录的信息保存在session当中
登录的时候,通过req.getSession()来创建一个session对象。
并且把userName存放到session域当中。
约定需要跳转的路径(/index)
@WebServlet("/login")
public class Servlet5 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
//处理用户请求
String userName=req.getParameter("userName");
String password=req.getParameter("password");
//此处简单模拟一下登录成功的情况
if("张三".equals(userName)&& "123".equals(password)){
//往会话当中存储键值对:用于保存用户登录的信息
//此处指定的参数为true,那么:需要此时会创建一个sesion对象
HttpSession session=req.getSession(true);
//把用户名存入session当中,代表用户已经登录成功了
session.setAttribute("userName",userName);
resp.sendRedirect("index");
}else{
//登录失败
resp.getWriter().write("login faild");
}
}
}
第四步:编写访问index页面的servlet
再次调用req.getSession方法,但是此处需要指定参数为false
因为此处的session就是为了验证用户登录与否,无需再次创建新的会话。
此处的session对象和第三步当中的session期待是同一个session对象。
因为期待是同一个会话。
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取到用户名
//此处getSession参数为false,原因:此处已经创建过会话了
HttpSession session =req.getSession(false);
resp.setCharacterEncoding("utf-8");
//根据key来获取value
String userName= (String) session.getAttribute("userName");
//返回一个主页
resp.getWriter().write("<h3>欢迎你!"+userName);
}
}
实现一个用户访问页面的次数的功能
无需太大的改动。只需在用户登录的时候,设置一个count统计用户登录的次数。这一个count需要使用session保存。
然后在页面(index)处,每一次用户取出来数据,都要+1。
代码实现:
登录页面
@WebServlet("/login")
public class Servlet5 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
//处理用户请求
String userName=req.getParameter("userName");
String password=req.getParameter("password");
//此处简单模拟一下登录成功的情况
System.out.println(userName+"..."+password);
if("张三".equals(userName)&& "123".equals(password)){
//往会话当中存储键值对:用于保存用户登录的信息
//此处指定的参数为true,那么:需要此时会创建一个sesion对象
HttpSession session=req.getSession(true);
//把用户名存入session当中,代表用户已经登录成功了
session.setAttribute("userName",userName);
//登录成功,默认初始的值为0
session.setAttribute("count",0);
resp.sendRedirect("index");
}else{
//登录失败
resp.getWriter().write("login faild");
}
}
}
index页面
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取到用户名
//此处getSession参数为false,原因:此处已经创建过会话了
HttpSession session =req.getSession(false);
//根据key来获取value
String userName= (String) session.getAttribute("userName");
resp.setCharacterEncoding("utf-8");
//获取一个count的值
Integer count= (Integer) session.getAttribute("count");
Integer newCount=count+1;
//在session当中保存自增过后的count
session.setAttribute("count",newCount);
//返回一个主页
resp.getWriter().write("<h3>欢迎你!"+userName+"您访问此页面的次数为:"+newCount);
}
}
如果在其中一个浏览器登录了,可以在另外一个浏览器直接访问登录页面吗?
不行的。来做个实验看一下:
首先,启动Tomcat,默认在360安全浏览器打开页面。
然后登录(登录的接口跟上面的是一样的,都是/login),同时使用Fidler抓包
然后,再抓一下访问index页面的URL的包:
换一个浏览器,再次访问index页面的URL
可以看到,换了一个浏览器,因为cookie当中包含的sessionID不一样了,也就没有办法保存原来sessionid当中的值,那么就无法获取到在原来的浏览器保存的session信息了。
(每一个浏览器都会有自己的cookie,也就意味着不同的浏览器有不同的sessionId)
总结:cookie和session的区别
使用对象 | 数据类型 | 安全性 | 存储大小 | 存储位置 | |
cookie | 针对网站: 每一个网站都会被分配一组cookie | (String,String) | 比较低,容易丢失、篡改 | 较小;一个cookie不超过3K | 保存在客户端浏览器(磁盘) |
session | 针对用户: 只有客户端才可以访问。 程序为客户端添加一个sessionId. 每一个sessionId对应一个HttpSession对象 | (String,Object) | 比较高 | 可以存储任意大的数据 | 保存在服务端 |