Session 和 cookie
一、Cookie
Cookie是什么呢?Cookie,有时也用其复数形式 Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息-----来自维基百科。用一句话来讲,就是存储在客户端服务器上的数据,是由网景公司(也就是这个公司发明了浏览器哦)发明的一种网络会话状态跟踪技术。
1.1 会话
可能有人会提出疑问,网络会话状态又是什么呢?首先我们要弄清网络会话,会话,字面意思上就是一次交谈,就客户端A和服务端B就可以类比成两个人小A和小B,一次会话就是AB之间的一次对话。如果用专业点的术语来讲的话(●’◡’●),就是一次请求与响应。
在一次请求和响应中,肯定是有数据传递的,所以这时,就需要会话状态跟踪 来查看数据在这次会话中的状态,但是在网络层的Http协议是无状态的。
小插曲:无状态是什么?
也就是当我们的小A和小B在进行通话完毕后,他们第二次又见面了,但是他们对上一次的会话一点都不记得了(当然现实中不太可能啦),也就是相当于丢失了在上次会话中的状态。
所以Cookie是由服务器并存放在客户端的一种信息载体,存有这次会话的信息,只要Cookie没有被清空,或者Cookie没有失效,那么会话状态就是有效的。
1.2 Cookie在会话中的状态
用户在第一次请求后,由服务器生成Cookie,并将其封装到响应头中,以响应的方式发送给客户端,客户端接受到这个请求后,保存到客户端。当客户端再次发同类请求,那么就会将Cookie携带上,以此作为凭证,来访问服务端作校验。
1.3 Cookie本质
其实Cookie本质是多个Key-value键值对而已。但是针对不同的浏览器,Cookie的保存方式和保存的位置都不一样。
1.4 JavaEE下的Cookie
常用API
public class ServletDome extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException{
//利用唯一的构造函数狗杂Cookie
Cookie cookie=new Cookie("key","value");
//绑定这个Cookie是在哪个资源路径下的,注意,这里必须要绑定项目名称
cookie.setPath(req.getContextPath()+"/a/b");
/**
* @target 设置这个Cookie的过时时间,单位是秒
* 如果时间大于0则需要将这个cookie存入外存中
* 时间小于就是存在内存(缓存中),关闭页面就消失
* 时间等于0就是一旦产生就马上失效
*/
cookie.setMaxAge(60*60);
//在HTTP Servlet Response中添加这个Cookie键值对
resp.addCookie(cookie);
}
}
public class ServletGetCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求中的Cookie信息
Cookie[] cookies=req.getCookies();
for(Cookie c:cookies){
System.out.println(c.getName()+"======="+c.getValue());
}
}
}
1.5 域属性空间
总的来说一共有三个域属性空间,在使用时优先肯定是使用小的,方便于保障数据的安全性,由大到小依次是:
- ServletContext:
是属于域的,可以完成跨会话的共享数据
-
HttpSession
置入其中的域属性是会话范围的,可以完成同类请求下的访问共享数据
-
HttpServletRequest
置入其实中的域属性只有在当前的请求路径下,可以完成跨Servlet共享数据
二、Session
2.1 Session
Session也是一种会话状态跟踪技术。当然前面所讲述的Cookie也是同样目的的技术。但是两者并不冲突,通常是将两者进行混合使用,因为Session是将相关数据保存在服务器端的,并不是在客户端。
Session是整个Web应用中所使用的,是以javax.servlet.http.HttpSession的接口对象的形式出现。
2.2 域属性空间
Session,简称为域。其实也就是HttpSession,是可以进行跨请求的。
其中有三个方法可以对其数据进行写和读:
-
setAttribute(Stirng name,Object value)
用于存放数据
-
getAttribute(String name)
用于获取Value
-
removeAttribute(String name)
用于删除
2.3 Sesion的具体使用
public class SomeServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
//获取用户提交的参数
String username=request.getParameter("username");
//将参数放入request域
request.setAttribute("user",username);
//获取Session对象
HttpSession session=request.getSession(false);
//在session域中写入属性
session.setAttribute("username",username);
response.getWriter().print("SomeServlet: "+username);
}
}
public class OtherServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String user=req.getParameter("user");
//获取Session
HttpSession session=req.getSession(false);
//从Session中读取指定属性
String username=null;
if (session!=null){
username= (String) session.getAttribute("username");
}
PrintWriter out=resp.getWriter();
out.print("OtherServlet:user: "+user);
out.print("OtherServlet:username: "+username);
}
}
2.4 Session工作原理
在系统中会对每一个会话维护一个Session会话,这里扩展下前面的域属性空间,其中,跨域,是指可以跨越不同的服务器;跨请求,是指可以跨越不同的工程;跨Servlet是指可以跨越不同的具体资源。(HttpSession的具体实现类是在Tomcat中的)
-
写入Session列表
服务器对当前的Session是以Map管理的,也就是Session列表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mltw3ewn-1588090079713)(D:\App\Typora\resources\md-image\Session和Cookie\image-20200428222809253.png)]
key是以32位长度的随机串,被称作JSessionID
value是Session对象的引用
当用户第一次提交请求时,服务端Servlet中执行request.getSession()后,会自动生成一个Map.Entry对象,然后存入key-value;
-
服务器生成并发送Cookie
在服务端存入了相应的Session信息后,系统还会自动将“JSESSIONID”作为key,sessionid作为value,放到response的头中去,并存入客户端,这个也就是Cookie。
-
客户端接受并发送Cookie
客户端将接受到的JSESSIONID这个Cookie放入缓存中,当用户第二次访问的时候,会将缓存中这个Cookie,伴随着请求头的头部信息,一起发送出去。
2.5 Session的失效
我们在平时会发现,当我们长时间不去登录一个网站后,本来会自动显示的账号提示信息会消失不见(这个信息也是由session存放的)。其实这个因为Session失效了。那么什么是失效呢?
首先,我们可以在web.xml中设置session的超时时间(默默提一句,为什么是在web.xml中设置,因为HttpSession的具体实现类是在Tomcat中实现的)
<session-config>
<!--以分钟为单位-->
<session-timeout>10</session-timeout>
</session-config>
或者在Java代码中,拿到session对象调用invalidate方法
那么什么时候会失效呢?我们把页面关了算不算以及失效了呢?在平时我们总是这样认为,但其实并不是。在上面我们已经知道session的真正引用会存储在服务端,所以当我们没用Cookie这个凭证时,我们直接拿那32位的门票进去也可以获取到那个Session的引用。所以只有当我们等服务端的session真正失效后才总算是真正安全的。
2.6 重定向和转发的番外
当我们在禁用Cookie后,上面提到了,我们扔可以通过JSeesionID来获取到Session对象。但是当我们重定向时禁掉Cookie时怎么获取那个重定向后的数据呢?我们可以encode来自动通过上面的方法来访问重定向后的禁用掉Cookie的网站
String url=req.getContextPath()+"someSevlet";
url=resp.encodeRedirectURL(url);
resp.sendRedirect(url);
转发也是如此,只是调用的函数不同罢了:
String url=req.getContextPath()+"someSevlet";
url=resp.encodeURL(url);
resp.sendRedirect(url);
)+"someSevlet";
url=resp.encodeRedirectURL(url);
resp.sendRedirect(url);
转发也是如此,只是调用的函数不同罢了:
String url=req.getContextPath()+"someSevlet";
url=resp.encodeURL(url);
resp.sendRedirect(url);