目录
Http的特点是无状态,就是当浏览器去访问服务端时,服务端不会记录客户端浏览器的访问状态,所以如果浏览器再次去访问服务端,还是将客户端当做“新人”对待
但是有些时候我们是需要服务端能够记录客户端的访问状态的,等下次客户端再次访问时服务器就可以识别客户端了,在Servlet中提供了Cookie和HttpSession对象用于维持客户端与服务端的会话状态,但是这两者是不同的,我们这里以一个饭店的例子将这两个对象划分:
一个饭店,现在我推出一个活动,用户累计消费100元,送一盘馒头:
Cookie对象:此时一位客人来吃饭,吃了50元前台结账后,前台姐姐写了一张纸条,上面写着消费50元,然后将这张纸条交给了客人,客人踹兜里了,而第二次这个客人来吃饭时,客人带着这个纸条来了,此时客人又消费了50元,刚好满了100元,送了一盘馒头
HttpSession对象:此时一位客人来吃饭,吃了50元前台结账后前台姐姐写了一个本子,在上面写上了你的姓名,消费50元并且添加了一个编号,然后再给客户写了一张纸条,上面写着本子上对应的编号。第二次这个客人带着这个纸条又来消费了,又消费了50元,前台姐姐拿着你的小纸条通过编号在小本子上一个一个找,找到了,送了一盘馒头
例子讲完了,两个例子中,纸条对应的就是Cookie对象,本子对应的就是HttpSession对象,但是HttpSession对象还是需要Cookie对象的辅助的
Cookie使用字符串存储数据
Cookie使用key与value的形式存储数据
Cookie存储的数据不支持中文,Servlet4.0开始支持
Cookie存储的数据长度不得超过4097个字节
Cookie是与域名绑定所以不支持跨一级域名访问
Cookie对象保持在客户端
每个浏览器对同一个域名的Cookie数量有限制,谷歌限制一个域名最多有50个Cookie对象
浏览器每次请求时都会把这个域名的所有Cookie对象带过来
通过Cookie对象的源码发现,可以直接通过new关键字创建Cookie对象,并且需要两个参数
第一个参数:key
第二个参数:value
- public class TestCookie extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- this.doPost(req,resp);
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //创建Cookie对象
- Cookie cookie = new Cookie("key","一拳超人");
- }
- }
通过HttpServletResponse对象下的addCookie("Cookie对象")方法将Cookie对象响应给客户端
- public class TestCookie extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- this.doPost(req,resp);
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //创建Cookie对象
- Cookie cookie = new Cookie("key","一拳超人");
-
- //将Cookie对象响应给客户端
- resp.addCookie(cookie);
- }
- }
注意:不管怎样,Servlet写完之后先去web.xml添加url和servlet的映射
浏览器每次请求时都会把与当前访问的域名相关的Cookie在请求中提交到服务端。通过HttpServletRequest对象获取Cookie,返回Cookie数组。
通过req的getCookies()方法获取一个Cookie数组
获取Cookie对象的name(getName() )
获取Cookie对象的value(getValue() )
刚刚我们添加了创建Cookie的Servlet,现在我们再添加一个获取Cookie的Servlet
- public class TestGetCookie extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- this.doPost(req,resp);
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //设置响应编码
- resp.setContentType("text/plain;charset=utf-8");
-
- //获取Cookie对象
- Cookie[] cookies = req.getCookies();
- //获取响应输出流
- PrintWriter pw = resp.getWriter();
- //循环遍历获取key(name)和value
- for (int i = 0; i < cookies.length; i++){
- String name = cookies[i].getName();
- String value = cookies[i].getValue();
- pw.println(name+"="+value);
- }
- pw.flush();
- pw.close();
- }
- }
编写完Servlet过后再web.xml文件中添加Servlet和url的映射
然后我们就可以启动Tomcat,测试创建Cookie,与获取Cookie
创建Cookie
获取Cookie
在Cookie中name的值不能使用中文,value的值可以是中文,但是在Servlet4.0之前Cookie的value也是不支持中文的,所以如果是Servlet4.0之前的兄弟就比较难受,但是如果是Servlet4.0之前也可以通过一些方法实现name和value支持中文的
我们可以通过对含有中文的数据重新进行编码来解决该问题
我们对创建Cookie的Servlet改造一下,对每个Cookie的name和value都进行了编码,以utf-8的形式进行编码
- public class TestCookie extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- this.doPost(req,resp);
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //创建Cookie对象
- Cookie cookie = new Cookie(URLEncoder.encode("key","utf-8"),URLEncoder.encode("一拳超人","utf-8"));
- Cookie cookie1 = new Cookie(URLEncoder.encode("动物","utf-8"),URLEncoder.encode("猫","utf-8"));
-
- //将Cookie对象响应给客户端
- resp.addCookie(cookie);
- resp.addCookie(cookie1);
- }
- }
既然进行了编码,那么在获取了Cookie对象后肯定要进行解码,所以我们还需要对获取Cookie对象的Servlet进行改造
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //设置响应编码
- resp.setContentType("text/plain;charset=utf-8");
-
- //获取Cookie对象
- Cookie[] cookies = req.getCookies();
- //获取响应输出流
- PrintWriter pw = resp.getWriter();
- //循环遍历获取key(name)和value
- for (int i = 0; i < cookies.length; i++){
- String name = URLDecoder.decode(cookies[i].getName(),"utf-8");
- String value = URLDecoder.decode(cookies[i].getValue(),"utf-8");
- pw.println(name+"="+value);
- }
- pw.flush();
- pw.close();
- }
这时候我们再去创建Cookie对象我们通过开发工具查看Cookie的name与value,这时我们会发现中文部分的name和value都是一些16进制数字,
我们再去获取Cookie对象的数据就可以支持中文了
那么给Cookie对象的数据添加编码的作用是什么呢?其实我也不是很清楚,但是我觉得可以这么去理解:
当我们给Cookie对象的数据进行编码过后相当于提醒Cookie,给这个数据添加编码然后直接响应给客户端
当我们再去获取Cookie对象的数据时,因为他添加了编码,我们肯定需要解码嘛,就跟压缩包一样,我们给他压缩了然后响应给了客户端,我们再去获取的时候肯定也是一个压缩包,所以我们需要对这个压缩包进行解压,以什么方式编码的,就以什么方式解码
域名分类:域名分为顶级域、顶级域名(一级域名)、二级域名。
域名等级的区别:一级域名比二级域名更高级,二级域名是依附于一级域名之下的附属分区域名,即二级域名是一级域名的细化分级。例如:baidu.com 为一级域名,news.baidu.com为二级域名。
Cookie不支持一级域名的跨域,支持二级域名的跨域。
也就是说同一个域名是可以共享Cookie对象,以最上面那个饭店的例子来讲,饭店是不是有很多不同的牌子,域名就相当于饭店的总部,同一个牌子的推出的活动在同一个牌子的饭店都可以享受到这个活动,但是如果a饭店推出了某个活动,你不可能去b饭店去享受这个活动把,就像麦当劳退出活动,你去肯德基,那怎么可能或享受到这个活动呢
根据Cookie的特点我们可以知道,Cookie对象默认是状态的,也就是说如果浏览器关闭过后,那么Cookie对象也会随之销毁,那么有些Cookie需要持久存在怎么办呢?就可以使用持久化Cookie的方式将Cookie响应个客户端
状态Cookie:
Cookie对象仅会被缓存在浏览器所在的内存中,当浏览器关闭Cookie对象也会被销毁
持久化Cookie:
浏览器对Cookie做持久化处理,浏览器关闭后再打开还可以找到Cookie对象,基于文件夹形式保存在系统指定的目录中。
Cookie对象的setMaxAge(秒数):
当Cookie对象创建后 默认为状态Cookie。可以使用Cookie对象下的cookie.setMaxAge(60)方法设置失效时间,单位为秒。
一旦设置了失效时间,那么该Cookie为持久化Cookie,浏览器会将Cookie对象持久化到磁盘中。当失效时间到达后文件删除。
session对象保存在服务端
使用key与value的方式存储数据
key是字符串类型,value是Object类型
存储数据大小无限制
HttpSession对象不是由我们来创建了,而是通过HttpRequest对象的getSession()方法来创建的,客户端浏览器在请求资源时:
1、如果在请求中没有jsessionid,getSession()方法将会为这个客户端浏览器创建一个新的HttpSession对象,并产生一个jsessionid,在响应中通过状态Cookie的方式将jsessionid响应给客户端(服务端返回的是状态Cookie对象,浏览器关闭了Cookie将被销毁,但是Session不会被销毁)
2、如果在请求中有jsessionid,getSession()方法将会在HttpSession对象中寻找这个对应jsessionid的数据
getSession()方法还有一个重载方法getSession(true|false)。
当参数为true时与getSession()方法作用相同。
当参数为false时则只去根据jsessionid查找是否有与这个客户端浏览器对应的HttpSession,如果有则返回,如果没有jsessionid则不会创建新的HttpSession对象。
注意:
一个浏览器对应一个session,不同的浏览器对应不同的session
- public class TestCreateSession extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- this.doPost(req,resp);
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //创建Session对象(一个浏览器对应一个Session对象)
- HttpSession session = req.getSession();
- }
- }
session.setAttribute("key",value)
将数据存储到HttpSession对象中
Object value = session.getAttribute("key")
根据key获取HttpSession中的数据,返回Object
Enumeration attributeNames = session.getAttributeNames()
获取HttpSession中所有的key,返回枚举类型
session.removeAttribute("key")
根据key删除HttpSession中的数据
String id = session.getId()
根据获取当前HttpSession的SessionID,返回字符串类型
例子:
创建一个Servlet创建Session对象
- public class TestCreateSession extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- this.doPost(req,resp);
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //创建Session对象(一个浏览器对应一个Session对象)
- HttpSession session = req.getSession();
- //session对象添加数据
- session.setAttribute("超人","一拳超人");
- }
- }
创建一个Servlet获取Session对象的id和数据
- public class TestGetSession extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- this.doPost(req,resp);
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- //获取Session对象,如果没有则不会创建
- HttpSession session = req.getSession(false);
- //获取jsessionid
- String id = session.getId();
- //获取数据
- String value = (String)session.getAttribute("超人");
-
- //设置响应编码
- resp.setContentType("text/plain;charset=utf-8");
-
- PrintWriter pw = resp.getWriter();
- pw.println("jsessionid="+id);
- pw.println("超人="+value);
-
- pw.flush();
- pw.close();
- }
- }
在编写完Servlet过后一定要在web.xml文件中添加Servlet和url的映射,因为Tomcat在启动后会先编译这个web.xml文件,然后再通过解析浏览器发出请求的url,找到url对应的Servlet
访问了testCreateSession.do后,我们可以发现Cookie中多了一个jsessionid
通过访问testGetSession.do我们可以获取到jsessionid和超人对应的数据
我们在将HttpSession的创建的时候说过服务端返回的是状态Cookie对象,浏览器关闭了Cookie将被销毁,但是Session不会被销毁
我们可以在web.xml文件中指定HttpSession的超时时间,当到达指定的超时时间后,容器就会销该HttpSession对象,单位为分钟。该时间对整个web项目中的所有HttpSession对象有效。时间的计算方式是根据最后一次请求时间作为起始时间。只要用户继续访问,服务器就会更新HttpSession的最后访问时间,并维护该HttpSession。用户每访问服务器一次,无论是否读写HttpSession,服务器都认为该用户的HttpSession"活跃(active)"了一次,销毁时间则会重新计算。如果有哪个客户端浏览器对应的HttpSession的失效时间已到,那么与该客户端浏览器对应的HttpSession对象就会被销毁。其他客户端浏览器对应的HttpSession对象会继续保存不会被销毁。
1、我们也可以在Tomcat的web.xml文件中配置HttpSession的销毁时间。如果在Tomcat的web.xml文件中配置了HttpSession的超时时间对应的是Tomcat中所有的Web项目都有效。相当于配置了全局的HttpSession超时时间。如果我们在Web项目中配置了超时时间,那么会以Web项目中的超时时间为准。
2、invalidate()方法是HttpSession对象中所提供的用于销毁当前HttpSession的方法。我们通过调用该方法可以销毁当前HttpSession对象。
在HttpSession对象生命周期中没有固定的创建时间与销毁时间。
1、何时创建取决于我们什么时候第一次调用了getSession()或getSession(true)的方法。
2、HttpSession对象的销毁时间取决于超时时间的到达或者调用了invalidate()方法。如果没有超时或者没有调用invalidate()方法,那么HttpSession会一直存储。默认超时时间为30分钟(Tomcat的web.xml文件配置的时间就是默认超时时间)。
Cookie对象保存在客户端,HttpSession保存在服务端
Cookie对象不安全,HttpSession对象安全
Cookie有大小限制,HttpSession没有大小限制
Cookie的value是String类型,HttpSession的value是Object类型