重新学习Cookie与Session

一. Cookie

1.1 设置cookie

  • 是由网景公司的前雇员卢在1993年3月发明的
  • 由来:以前的公司在十点到十点半是上午茶的时间,有个人很喜欢吃小甜饼,吃的久了,身上就带了这个味道。他从别人经过的时候别人闻到了小甜饼的味道就知道是他,所以我们在请求的时候带上cookie就知道是谁了。
  • 是一种会话跟踪技术。
  • 由于http 请求是无状态的,第一次的请求-响应不会影响下一次的请求-响应。
  • 是由服务器发出的,客户端保存的。
  • 可分为内存Cookie和硬盘Cookie new Cookie(k, v).setMaxAge(保存多少秒);setMaxAge()>0时保存在硬盘上 <= 0 的时候保存在内存中。
    下面我们看代码实现:
@Controller("/qwe")
@RequestMapping("/qwe")
public class CookieTest {
    
    @Autowired
    private HttpServletRequest request;

    @Autowired
    private HttpServletResponse response;

    @RequestMapping(value = "/asd",method = {RequestMethod.GET})
    @ResponseBody
    public String test(){
        //创建两个cookie
        Cookie cookie1 = new Cookie("teacher", "oneToThree");
        Cookie cookie2 = new Cookie("worker_niudun", "nihaoa");
        //指定cookie的资源路径
        cookie1.setPath(request.getContextPath() + "/xxx/eee");
        cookie2.setPath(request.getContextPath() + "/ggg");
        //设置cookie有消息为10天
        cookie1.setMaxAge(60 * 60 * 24 * 10);
        System.out.println(request.getContextPath());
        response.addCookie(cookie1);
        response.addCookie(cookie2);
        return "你好啊" + request.getContextPath();
    }
}

cookie1.setPath(request.getContextPath() + "/xxx/eee"); 这个的意思是以后访问http://localhost:8080/qwe/asd/ 这个资源路径下的文件都会在请求头上带上这个cookie
我们试着访问下一个不存在的资源路径:结果显示带上了这个cookie
在这里插入图片描述
我们看下浏览器端显示的cookie信息:
在这里插入图片描述
在这里插入图片描述

1.2 获取cookie

@RequestMapping(value = "/asd/q",method = {RequestMethod.GET})
    @ResponseBody
    public void getCookieName(){
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie:cookies) {
            System.out.println(cookie.getName());
        }
    }

在request请求中我们可以看到:
在这里插入图片描述

二. 域属性空间对比

  • ServletContext :域属性是整个范围的 可以跨会话共享数据
  • HttpSession :会话范围 可以跨请求共享数据
  • HttpServletRequest: 一次请求范围内 可以跨Servlet请求数据 但必须在一个请求中
    在保证需求的情况下使用小范围的比较好,节省服务器内存,安全性更高(数据放的时间越长 约占内存 也越不安全)
  • Session:同一会话可以跨请求传递数据。

三. Session

  • 是一个会话 可跨请求共享数据

3.1 怎么使用?

首先我们新建一个请求/a 然后我们分别往request域,session域中放入数据,看我们另外一个请求能否拿到数据

@RequestMapping(value = "/a",method = {RequestMethod.GET})
    @ResponseBody
    public void test() throws IOException {
        String username = "lisi";
        //参数放入request域中
        request.setAttribute("user", username);
        //获取session
        HttpSession session = request.getSession();
        //像session中写入属性
        session.setAttribute("username", username);
        response.getWriter().println("username:"+username);
    }

我们新建的请求/b

RequestMapping(value = "/b",method = {RequestMethod.GET})
    @ResponseBody
    public void getCookieName() throws IOException {
        String str = "";
        //从request域中读取属性
        str = request.getParameter("user");
        //获取session
        HttpSession session = request.getSession(false);
        String username = "";
        //从Session域中读取指定属性
        if(session != null){
            username = (String) session.getAttribute("username");
        }
        response.getWriter().println("user:"+str);
        response.getWriter().println("username:"+username);
        response.getWriter().println("session:"+session);

    }
  • 结果展示
    在这里插入图片描述
    在这里插入图片描述
    结果中我们可以看到request 域里面的数据只能在一个请求中,session的数据可以在不同请求

3.2 对于request.getSession()的用法

  • 若要像session写入数据则用getSession(true)getSession()。意义是有老的用老的,没有则创建一个新的
  • 若要使从session读取数据则使用getSession(false) 意义是有老的用老的没有则返回null 。因为新的session也没有我们要的数据。

3.3 Session 工作原理

服务区会为每一个会话维护一个session 不同的会话对应不同的session,那么系统是如何识别每一个各个不同的sesion对象呢?如何做到统一会话过程中使用的是同一个session呢?

  • (一)写入Session列表
    服务器对应的Seesion是以map的形式进行管理的,这个map称为Session列表key是一个32位的随字符串,这个字符串称为JSESSIONID,value则是session对象的引用
    服务器servlet遇到request.getSession()的时候 会自动生成一个Map.Entry对象,key为根据某种算法生成的JSESSIONID,value是新创建的session对象。就把这个<K, V>写到session列表中了。

  • (二)服务器生成并发送Cookie
    在上一步骤,服务器生成map对象后同时生成一个cookie放到响应头中,name就是JSESSIONID,value就是这个32位的字符串。

SESSION=OWM5NDdiMjItOTRjMC00ZThlLTg4YjctZGY4MzEyYzEwN2Fi

在这里插入图片描述

  • (三)客户端接受并发送cookie
    客户端接受到这个cookie会把这个保存到浏览器的缓存中。只要浏览器不关闭,cookie就不会消失。
    当用户提交第二次请求的时候会把缓存中的cookie带上,放到请求头中一起发到服务器中。如下图:在request中带上了刚才服务器生成的cookie
SESSION=OWM5NDdiMjItOTRjMC00ZThlLTg4YjctZGY4MzEyYzEwN2Fi

在这里插入图片描述

  • (四)从Session列表中寻找
    服务器从请求中读取到客户端发来的cookie,然后拿着这个cookie中的32位字符串去自己的session列表中查找,找到了对应的session对象,然后可以开始对该对对象的域属性读写操作。

3.4 Session 失效

    1. 在项目的web.xml中设置

单位是分钟

<session-config> 
<session-timeout>15</session-timeout> 
</session-config> 
    1. 手动调用sessioninvalidate方法session.invalidate();

对于用户来说:关闭浏览器算是会话结束
对于服务器来说:session失效算会话结束

3.5 禁用Cookie后使用重定向跳转时Session的跟踪

使用response.encodeRedirectURL(uri);来对重定向进行session跟踪

@RequestMapping(value = "/a",method = {RequestMethod.GET})
    @ResponseBody
    public void test() throws IOException {
        String username = "lisi";
        request.setAttribute("user", username);
        HttpSession session = request.getSession();
        session.setAttribute("username", username);
        System.out.println("/a session:"+session);
        String uri = "/qqq/b";
        uri = response.encodeRedirectURL(uri);
        response.sendRedirect(uri);
    }

3.6 禁用Cookie后使用非重定向跳转时Session的跟踪

使用response.encodeURL(uri);

@RequestMapping(value = "/a",method = {RequestMethod.GET})
    @ResponseBody
    public void test() throws IOException {
        String username = "lisi";
        request.setAttribute("user", username);
        HttpSession session = request.getSession();
        session.setAttribute("username", username);
        System.out.println("/a session:"+session);
        String uri = "/qqq/b";
        uri = response.encodeURL(uri);
		response.getWriter().println("<a href='"+uri+"> 跳转</a>到Servlet");
    }
发布了118 篇原创文章 · 获赞 5 · 访问量 8732

猜你喜欢

转载自blog.csdn.net/weixin_43672855/article/details/104707368