Cookie 和 Session 详解
一、会话的概念
会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾经来过,这称之为有状态会话。
二、会话过程中要解决的一些问题?
每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,程序要想办法为每个用户保存这些数据。
三、保存会话数据的两种技术
3.1、Cookie
Cookie的由来
-
首先我们需要介绍一下,在Web开发过程中为什么会引入Cookie。我们知道Http协议是一种无状态协议,
Web服务器本身不能识别出哪些请求是同一个浏览器发出的,浏览器的每一次请求都是完全孤立的。
即便在Http1.1支持了持续连接,但当用户有一段时间没有提交请求时,连接也会自动关闭。这时,作为Web服务器,
必须采用一种机制来唯一标识一个用户,同时记录该用户的状态。于是就引入了第一种机制:Cookie机制。 -
Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
-
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
-
Cookie保存在客户端,只能保存字符串对象,不能保存对象类型,需要客户端浏览器的支持:客户端可以不支持,因为浏览器用户可能会禁用Cookie。
Cookie的定义即基本介绍
Cookie是在浏览器访问WEB服务器的某个资源时,
由WEB服务器在HTTP响应消息头中附带传送给浏览器的一个小文本文件。
- 一旦WEB浏览器保存了某个Cookie,
那么它在以后每次访问该WEB服务器时,
都会在HTTP请求头中将这个Cookie回传给WEB服务器。 - 一个Cookie只能标识一种信息,
它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。 - 一个WEB站点可以给一个WEB浏览器发送多个Cookie,
一个WEB浏览器也可以存储多个WEB站点提供的Cookie。 - 浏览器一般只允许存放300个Cookie,
每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
Cookie的原理
底层的实现原理: WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,
浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给WEB服务器。
Cookie的操作
创建、添加、设置时间、删除
public Cookie(String name, String value) ; // 创建cookie
public void setComment(String purpose); // 设置cookie的描述
public void setMaxAge(int expiry) // 设置 cookie的时间 单位为秒
public String getName() // 获得存的cookie的名字
public String getValue() // 获的cookie的值
// 删除的话 是设置时间为 0
3.2、Session
概述
- Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
- 之前我们介绍的cookie是把用户的身份信息存在了客户端,而session说白了就是把用户的信息保存在了服务端。由于session是保存在了服务端,所以当用户关闭浏览器时session并不会消失。一般session保存在服务器的内存中当然也可以持久化到硬盘或者数据库中。session的默认过期时间是30分钟,过期的session会被服务器自动的销毁。注意如果大量的创建session可能导致服务器的内存溢出。
一、session的创建流程
当客户端浏览器访问服务器时,服务器会先检查该请求是否携带一个叫JESESSIONID的cookie,如果存在会根据JESESSIONID的cookie值获取存放在服务器端的session值;如果不存在会新建一个session然后把sessionId写到cookei中返回给浏览器,下次浏览器访问时就会携带这个cookie。
小demo
-
测试1 第一次登录不展示名字 第二次会展示存进去的值。
-
public class TestSessionServlet extends HttpServlet{ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); response.setCharacterEncoding("utf-8"); response.setHeader("content-type","text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); String loginName = (String) session.getAttribute("loginName"); String sessionId = session.getId(); if(StringUtils.isEmpty(loginName)){ session.setAttribute("loginName","张三"); writer.println("session中没有值!"); }else{ writer.println("loginName="+loginName); } writer.println("sessionId="+sessionId); writer.close(); } }
JavaWeb 中 Session 模拟登录、拦截
表单页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>login</title> </head> <body> <form action="${pageContext.request.contextPath}/sessionLogin" method="post"> 用户名:<input name="username" type="text"> 密码:<input name="password" type="password"> <input type="submit" value="Login"> </form> </body> </html>
里面用到的User类
/** * @author crush */ public class User { private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
处理登录的Servlet
/** * @author crush * 实现自动登录 */ @WebServlet("/sessionLogin") public class Login extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 开启session HttpSession session = req.getSession(); // 获取登录的参数 String username = req.getParameter("username"); String password=req.getParameter("password"); // 设置字符编码 resp.setContentType("text/html;charset=utf-8"); PrintWriter writer = resp.getWriter(); // 判断用户名和密码是否正确 if(username.equals("admin")&&password.equals("123456")){ // 存session session.setAttribute("user",new User(username,password)); session.setMaxInactiveInterval(200); writer.print("恭喜你登录成功!!!"); } else{ System.out.println("账号或密码错误"); resp.sendRedirect("/login.jsp"); } } }
mian2请求 测试是否登录的请求
/** * @author crush */ @WebServlet("/main2") public class Main extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); User user =(User) session.getAttribute("user"); // 设置字符编码 resp.setContentType("text/html;charset=utf-8"); if(user==null){ // 没有登录会转向登录页面 resp.sendRedirect("/login.jsp"); } else{ req.setAttribute("success","恭喜你做出了登录的小Demo!!!"); req.getRequestDispatcher("/hello.jsp").forward(req,resp); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
Hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>hello</title> </head> <body> ${success} <br> </body> </html>
自言自语
简单的一天。