Cookie、Session学习

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/xuruanshun/article/details/102664796

目录

1.会话概述

2.Cookie介绍&Cookie案例

2.1.Cookie技术概述

2.2.Cookie的API介绍

2.2.1.创建Cookie

2.2.2.获取Cookie

2.2.3.Cookie分类

2.2.4.设置路径

2.2.5.Cookie的有效域名(了解)

2.2.6.删除Cookie

2.3.cookie案例:显示用户上次访问的时间

3.Session

3.1.什么是session?

3.2.Session的API

3.2.1.获取Session对象

3.2.2.服务器端操作Session时细节

3.2.3.使用getSession方法的细节

3.3.思考:关闭浏览器后再次访问能获取到Session的数据吗?

3.4.禁用Cookie后Session追踪

3.5.Session对象的生命周期(面试)

3.6.Session案例一次性验证码登录

3.7.Servlet三种数据范围


 

1.会话概述

什么是会话?

用户打开浏览器,访问一个网站. 然后点击多个连接,访问这个网站的多个资源. 最后关闭浏览器的整个过程称之为一次会话.

会话过程中需要解决一些问题:

每个用户和服务器交互的会话过程中, 会产生一些数据,需要程序将数据保存起来.

 

 

2.Cookie介绍&Cookie案例

2.1.Cookie技术概述

用户打开浏览器开始访问服务器,在一系列的访问过程中,把用户的这些操作称为用户和服务器的之间的对话(客户端和服务器的会话)。在交互的过程中,用户的一系列操作,肯定会产生一些数据需要保存。这时就需要使用Java提供的Cookie或者Session技术来完成。

cookie的典型应用是:

判断用户是否登陆过网站,以便下次登录时能够直接登录。如果我们删除cookie,则每次登录必须从新填写登录的相关信息。

 

 

Cookie:它是服务器在获取到用户的请求之后,把用户的请求中的重要资源保存在这个对象中,在给用户响应的时候,把这个对象的发给客户端。然后浏览器接收到这个Cookie之后,浏览器会自动的把Cookie中的数据保存到浏览器管理的缓存中,下次用户在访问这个网站的时候,浏览器就会自动携带上次保存的Cookie中的数据到服务器,服务器进而就能获取到以前的信息。

 

总结:

Cookie是浏览器端的技术,因为cookie对象及信息保存在浏览器上;cookie对象是由服务器创建的

浏览器访问服务器的流程:

  • 浏览器第一次访问服务器,服务器端如果校验信息匹配则会创建cookie对象,将信息保存到cookie里,向浏览器回应响应,
  • 同时携带cookie给浏览器,由浏览器保存;浏览器会识别cookie,将cookie对象保存到浏览器缓存中;
  • 浏览器再次访问服务器,携带保存了信息的cookie,服务器识别cookie,取出里面的信息,并将含有信息的页面返回给浏览器,
  • 同时携带cookie到浏览器,以后每次浏览器和服务器的交互两者都会携带cookie,从后文可以看到;

 

 

2.2.Cookie的API介绍

问题:

1、如何创建cookie保存用户名和密码?

2、如何将cookie信息响应给浏览器?

3、如何在浏览器查看cookie的信息?

4、如何在服务器端查看浏览器请求携带的cookie信息?

5、关闭浏览器 再次请求是否携带cookie的信息?

6、告诉浏览器访问哪些页面才会携带cookie信息?

 

 

2.2.1.创建Cookie

创建一个 cookie,cookie 是 servlet 发送到 Web 浏览器的少量信息,这些信息由浏览器保存,然后发送回服务器。

cookie 的值可以唯一地标识客户端,因此 cookie 常用于会话管理。 一个 cookie 拥有一个名称、一个值和一些可选属性,比如注释、路径和域限定符、最大生存时间和版本号。一些 Web 浏览器在处理可选属性方面存在 bug,因此有节制地使用这些属性可提高 servlet 的互操作性。

servlet 通过使用 HttpServletResponse的addCookie 方法将cookie 发送到浏览器,该方法将字段添加到 HTTP 响应头。

 

通过Cookie的构造函数,告诉我们在服务器给响应数据的时候,如果要发送一个Cookie对象,这时需要在服务器先创建一个Cookie对象,而这个Cookie中保存的数据由key和value组成。

当浏览器下次再访问服务器的时候,就会携带这个Cookie对象到服务器,服务器就会获取到当前这个Cookie对象,然后需要通过这个key,找出value值。

需要把浏览器cookie发送给浏览器,需要借助response对象完成

response.addCookie(Cookie对象);

方法:

构造方法:Cookie (String name,String value)  服务器创建cookie对象

发送方法:addCookie(Cookie cookie)   服务器端由response对象发送cookie对象到浏览器

 

 

 

2.2.2.获取Cookie

指的是浏览器向服务器发送的cookie.

获取请求中的cookie 需要使用request对象。

request对象中的getCookies 获取到一个cookie数组,因此一个Servlet可以同时发送给客户端多个Cookie对象。

每个cookie对象中以键值对的形式保存信息,所以可以在多个cookie对象中保存多个信息(每个cookie只能保存一个,但可以有多个cookie)

 

2.2.3.Cookie分类

1、临时会话级别的Cookie

服务器给客户端发送的Cookie,如果没有指定Cookie在客户端的保存时间,这时这个Cookie只会在浏览器运行的期间存在;

当浏览器关闭之后,客户端中的Cookie随着浏览器的关闭就消失了。

2、持久化的Cookie

2.2.4.设置路径

 

2.2.5.Cookie的有效域名(了解)

2.2.6.删除Cookie

​​​​​​​2.3.cookie案例:显示用户上次访问的时间

整体代码:

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 需求: 显示用户上次访问的时间
		// 服务器接收浏览器传送的所有cookie
		Cookie[] cookies = request.getCookies();
		String lastVisitTime = null;
		// 判断
		if(cookies!=null) {
			// 遍历
			for(Cookie c : cookies) {
				// 获取cookie 的标识 和 值
				String name = c.getName();
				String value = c.getValue();
				// 通过判断获取上次访问的时间
				if("lastVisit".equals(name)) {
					// 获取上次访问时间
					lastVisitTime = value;
				}
			}
		}
		
		// 防止浏览器出现中文乱码
		response.setContentType("text/html;charset=utf-8");
		// 判断是否是初次访问
		if(lastVisitTime!=null) {
			// 说明不是初次访问  给浏览器显示上次访问的时间
			response.getWriter().println("您上次访问的时间是:" + lastVisitTime);
		} else {
			// 说明是第一次访问 给浏览器显示 欢迎首次登录
			response.getWriter().println("欢迎首次登录!");
		}
		
		String current_time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
		// 创建cookie 保存当前时间
		Cookie cookie = new Cookie("lastVisit", current_time);
		// 设置有效路径 "/" 表示 http://ip:端口
		// www.baidu.com 代替 百度服务器的ip地址:80
		cookie.setPath("/");
		// 设置最大生存时间
		cookie.setMaxAge(60 * 30);
		// 服务器给浏览器发送cookie
		response.addCookie(cookie);
	}

登录页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>登录表单</title>
  </head>
  
  <body>
  	<%
  		String usernameStr = null;
  		// 获取浏览器给服务器的所有cookie, 判断取出用户名
  		Cookie[] cookies = request.getCookies();
  		// 判断
  		if(cookies!=null) {
  			for(Cookie c : cookies){
  				String name = c.getName();
  				String value = c.getValue();
  				//判断取出用户名
  				if("username".equals(name)) {
  					usernameStr = value;
  				}
  			}
  		}
  	 %>
  	<font color="red">${requestScope.errorMsg}</font>
    <form action="/day12/login" method="post">
    	用户名 <input type="text" name="username" value='<%=usernameStr!=null?usernameStr:""%>'/><br/>
    	密码 <input type="text" name="password"/><br/>
    	<input type="submit" value="登录"/>
    </form>
  </body>
</html>

LoginServlet:

public class LoginServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 接受用户名和密码
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		// 校验用户名和密码是否合法:模拟数据库校验 假设用户名是zhangsan 密码是123
		if("zhangsan".equals(username) && "123".equals(password)) {
			// 如果合法 创建cookie 保存用户名,发送给浏览器保存; 跳转到欢迎页面, 并且显示用户名
			Cookie cookie = new Cookie("username", username);
			// 设置有效路径
			cookie.setPath("/");
			// 设置最大生存时间
			cookie.setMaxAge(60 * 60 * 24 * 10);
			// 向浏览器发送cookie
			response.addCookie(cookie);
			
			// 将用户名发到session中
			request.getSession().setAttribute("username", username);
			// 跳转到欢迎页面
			response.sendRedirect("/day12/welcome.jsp");
			return;
		} else {
			// 如果不合法 提示用户名或密码错误 将请求转发到登录页面
			request.setAttribute("errorMsg", "用户名或者密码错误!");
			request.getRequestDispatcher("/login.jsp").forward(request, response);
			return;
		}
	}
}

欢迎页面: welcome.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'welcome.jsp' starting page</title>
  </head>
  
  <body>
  	<!-- 从session中取出用户名 欢迎登录 -->
  	<%=session.getAttribute("username") %>, 欢迎登录!
  </body>
</html>

 

 

3.Session

Cookie技术可以将用户的信息保存在各自的浏览器中,

优点:很明显实现了同一个用户不同请求中数据共享。

缺点:黑客可以利用脚本等手段窃取cookie中的重要数据,从而泄漏个人的隐私,存在巨大的安全隐患。

session技术:是将会话的数据保存在服务器端的技术。

 

总结:

Cookie是浏览器端技术,由服务器端创建cookie对象,发送给浏览器,由浏览器端保存cookie对象

Session是服务器端技术,由服务器端自动创建session对象,并由服务器端保存session对象

注意:cookie众多对象中的含有唯一识别标志的cookie对象是由服务器端自动创建的,别的cookie我们可以自己创建;

 

3.1.什么是session?

session是服务端技术, 利用这个技术, 服务器运行时可以为每一个用户每一个浏览器创建一个独享的session对象.

Session对象可以作为容器使用,可以存储一些简单的数据,所以有时候将session对象也叫作session容器;

由于session对象为每个用户的浏览器独享,所以用户在访问服务器的web资源时,可以把用户各自的数据保存在session中;

当用户去访问服务器的其他资源时,可以取出从各自的session容器中取出数据为用户所用.

 

3.2.SessionAPI

3.2.1.获取Session对象

Session是基于用户的请求,而把用户的重要信息在服务器端针对这个用户(浏览器)创建了一个容器。

而这个Session容器是由web服务器(tomcat)帮助我们创建的,在程序中我们只能去获取这个容器,然后给容器添加数据或者取出数据,或者删除数据,而我们是不能创建这个容器对象

在HttpServletRequest对象中提供了获取session对象的方法:

使用request对象就可以获取到当前针对用户的请求服务器内部创建的那个Session容器对象。

HttpSession依然是一个接口,而这个接口的实现类有web服务器来提供。只要能够运行我们JavaEE项目的web访问前,它们都会实现Java提供的所有web技术中的接口。

 

 

 

 

3.2.2.服务器端操作Session时细节

其实服务器端可以识别每个用户的对应的Session容器,主要是因为服务器针对每个用户都发送了JSESSIONID(session容器的唯一标识)的Cookie信息。这样用户在操作的时候,都会携带这个Cookie到服务器端,因此服务器端才能识别针对当前这个用户的那个session容器对象。

服务器在给客户端响应数据的时候,把Session容器的唯一标识以Cookie的形式发送给浏览器,而这个Cookie是一个会话级别(临时)Cookie,它只能存活在浏览器运行的阶段,如果浏览器关闭了,这个Cookie信息就没有了,因此在此打开浏览器访问的时候,就不会在服务器获取到针对当前用户的JSESSIONID信息,因此无法找到针对当前用户的那个Session容器。

进一步说明,服务器端的Session容器对象,是针对每个浏览器的。

 

总结:

cookie对象默认浏览器关闭时自动销毁,但可以设置cookie的最大存活时间可以持久化cookie对象,因为session对象的使用是依赖于Cookie对象的,session对象的唯一标识保存在cookie中,所以可以通过cookie找到相应的session,也就是说,能否找到对应的session容器取决于cookie的生命周期;

 

3.2.3.使用getSession方法的细节

在API中提供2个获取Session对象的方法:

getSession()

         空参数的方法,在使用的时候,如果服务器端针对当前用户的浏览器没有Session容器,这时在服务器的内部会先创建一个Session对象,然后把这个Session对象返回给我们的程序。如果Session容器已经存在,这时它不会再创建新的Session容器对象,只是把找到的这个Session容器对象返回给程序。在找的过程中需要依赖于JSESSIONID。默认情况下,每次重启浏览器,第一次访问服务器时,就会创建一个session对象,后来再次访问服务器时,由于已经存在session对象了,所以就不会创建session对象了;

那么,有个问题,每次重启浏览器访问服务器时都会创建一个session对象,那么上次重启浏览器创建的session到哪里去了,

如果还存在在服务器中的话,我们此次只是根据此次生成的session对象的唯一标识可以找到此次生成的session对象,也就是说

服务器中还存在多个session对象,只是我们使用的是此次生成的session对象而已;答案后面继续探讨,我会给出的;

 

getSession(Boolean create):

如果这个在调用的时候,传递的值为false,它仅仅只会在容器根据JSESSIONID找有没有对应的Session容器对象,如果有就返回这个Session容器对象,如果没有,就返回null。如果传递的值true,在根据JSESSIONID找Session容器对象的时候,如果不存在就会创建一个新的Session容器对象,并返回这个容器对象,如果存在就直接返回存在的Session容器对象,同getSession()

 

 

3.3.思考:关闭浏览器后再次访问能获取到Session的数据吗?

一般情况下,关闭浏览器之后,再次访问,是无法获取到Session中的数据的。

因此在服务器针对当前用户的第一次请求创建的唯一的Session容器对象,而在给这次请求的之后,服务器需要给用户响应数据,在响应的时候,服务器把当前Session容器对象的JSESSIONID以Cookie的形式发送给了浏览器。而这个Cookie并没有设置有效时间,那么这个Cookie就属于临时Cookie,在关闭浏览器之后,再次打开浏览器的时候,上次的Cookie已经消失了,用户虽然拿同一个浏览器访问服务器,可是这时没有JSESSIONID,服务器端的Session容器依然存在,但是没有JSESSIONID,服务器内部无法获取到这个session对象

 

默认情况下重启浏览器无法获取到seesion的数据,因为默认情况下浏览器关闭时自动销毁cookie对象;那么可以通过持久化包含JSESSIONID的Cookie对象,重启浏览器后仍然根据cookie中的唯一标识找到session对象,进而获取seesion中的数据;

Session接口中的API:  String  getId():获取session对象的唯一标识

 

 

3.4.禁用Cookie后Session追踪

问题:服务器端获取Session对象依赖于客户端携带的Cookie中的JSESSIONID数据。如果用户把浏览器的隐私级别调到最高,这时浏览器是不会接受Cookie、这样导致永远在服务器端都拿不到的JSESSIONID信息。这样就导致服务器端的Session使用不了。

解决:Java针对Cookie禁用,给出了解决方案,依然可以保证JSESSIONID的传输。Java中给出了再所有的路径的后面拼接JSESSIONID信息。

 

 

如果不设置浏览器的隐私级别,则编码前后都是 /day11/session2,但是设置之后,编码前依旧是/day11/session2,但是编码后 /day11/session2 后多了一堆字符,这就是session的唯一标识;

通过唯一标识可以找到对应的session对象,获取数据。也就是说禁用cookie后只有将路径编码才可以生成session的唯一标识并找到session对象,获取数据,否则无法找到对应的session;

在response对象中的提供的encodeURL方法它只能对页面上的超链接或者是form表单中的action中的路径进行重写(拼接JSESSIONID)。

 

 

3.5.Session对象的生命周期(面试

我的理解:

  1. 关闭浏览器后,session就销毁了吗?

关闭浏览器后,默认销毁了cookie对象,但是session对象没有被立即销毁,session对象会保存在服务器内存默认30分钟,之后才会被销毁,但是关闭浏览器,立刻即销毁cookie对象,保存在cookie对象中的session对象的唯一标识也就销毁了,所以在服务器中就无法找到对应的session对象,也就是说,session对象的生命周期与浏览器关闭无关,只是关闭浏览器后就找不到session对象了而已,我们也就无法使用这个session对象了,重启浏览器会创建一个新的session对象;

 

  1. 创建session对象的时机?

第一次访问浏览器时,服务器的底层会默认调用getSession方法,此方法的作用是如果有session对象就获取session对象,如果没有session对象就创建并获取session对象,所以此方法的底层会先判断是否有session对象,由于是第一次访问,服务器没有session对象,就会创建session对象,这就是时机1;

如果手动的销毁session对象,那么服务器自然不会在此次会话中再自动的创建session对象了,这时候我们就可以收到的用getSession方法,

判断没有session对象后再创建对象,这就是时机2;

总之,创建session的方法是getSession方法,同时此方法可以获取session对象

注意:一次会化中,在浏览器只有第一个打开的页面才会创建session对象,之后在同一浏览器打开的多个页面中不会再创建session对象;

后面所说的session对象的生命周期为一次会话,不是说session对象销毁了,而是说我们不能使用此session对象了;

 

 

3.6.Session案例一次性验证码登录

表单: checkcode.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>登录表单</title>
    
   	<script type="text/javascript">
		function _click(){
			var d = new Date();
			document.getElementById("myImg").src = "/day11/checkcode?" + d.getMilliseconds();
		}
	</script>
  </head>
  
  <body>
  	<font color="red">${requestScope.errorMsg}</font>
    <form action="/day11/session3" method="post">
    	用户名 <input type="text" name="username"/><br/>
    	密码 <input type="text" name="password"/><br/>
    	
    	输入验证码 <input type="text" name="form_code"/>
    	<img src="/day11/checkcode" id="myImg" onclick="_click()"/> 
    	<a href="javascript:void(0)" onclick="_click()">看不清,换一张</a><br/>
    	
    	<input type="submit" value="登录"/>
    </form>
  </body>
</html>

生成验证码的servlet

package cn.itcast.session;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CheckcodeServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		int width = 120;
		int height = 40;
		// 生成一个画布, 理解成 一张画纸
		BufferedImage bufi = new BufferedImage(width , height , BufferedImage.TYPE_INT_RGB);
		// 从画布上获取画笔
		Graphics g = bufi.getGraphics();
		// 填充背景颜色
		g.setColor(Color.white);
		g.fillRect(0, 0, width, height);
		// 画边框
		g.setColor(Color.red);
		g.drawRect(0, 0, width-1, height-1);
		
		// 生成4个随机的字母数字的组合
		// 准备数据
		String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz";
		// 生成随机对象
		Random r = new Random();
		String sessionCode = "";
		// 生成4个随机的字母数字的组合
		for(int i=0; i<4; i++){
			// 设置字体
			g.setFont(new Font("黑体", Font.ITALIC, 30));
			// 设置字体的颜色
			g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
			String str = data.charAt(r.nextInt(data.length()))+"";
			// 向画布上写字
			g.drawString(str, 10+i*25, 30);
			
			sessionCode += str;
		}
		
		// 将生成的验证码保存到 session容器中
		request.getSession().setAttribute("session_code", sessionCode);
		
		// 画干扰线
		for(int i=0; i<10; i++){
			// 设置字体的颜色
			g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
			g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
		}
		
		// 将内存中的画纸 输出到浏览器中
		ImageIO.write(bufi, "jpg", response.getOutputStream());
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	}
}

校验验证码的servlet:

public class Session3Servlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 校验用户提交的验证码是否正确
		// 获取用户提交的验证码
		String formCode = request.getParameter("form_code");
		// 获取后台生成的验证码 (验证码保存在session容器中比较合适)
		HttpSession session = request.getSession();
		String sessionCode = (String) session.getAttribute("session_code");
		// 手动销毁session对象
		session.invalidate();
		// 如果验证码不正确, 提示验证码错误, 返回登录页面
		if(sessionCode==null ||  !sessionCode.equalsIgnoreCase(formCode)){
			// 提示用户验证码不正确,将错误信息返回给登录页面
			request.setAttribute("errorMsg", "验证码不正确!");
			// 请求转发到登录页面
			request.getRequestDispatcher("/login.jsp").forward(request, response);
			return;
		}
		
		// 如果验证码正确, 继续校验 用户名和密码
		response.setContentType("text/html;charset=utf-8");
		response.getWriter().println("继续校验 用户名和密码");
	}
}

3.7.Servlet三种数据范围

范围由大到小:

  • servlertContext 全局应用于整个项目;  session一次会话中;  request一次请求

存活时间由大到小:

  • servlertContext 项目运行中,一直存在
  • session  默认存活30分钟(一次会话中)
  • request  存活时间,请求响应一结束立刻销毁

 

下面的三个对象,可以当做容器来使用,可以保存数据,因此他们也被称为域对象。

  • ServletContext:它保存的数据所有的Servlet共享。它的范围最大。开发几乎不用。除非需要保存整个项目中共享的信息才会使用。
  • HttpSession:它是针对当前某个用户(浏览器)的一系列操作,然后在服务器端创建的一个容器,整个容器仅仅只能是当前这个客户端(浏览器)使用。多个客户端(浏览器),它们会有不同的Session容器对象
  • HttpServletRequest:它的针对用户的这次请求,只要请求和响应结束,这个容器就消失了。一般开发中这个容器是最常用。只要给request中保存了数据之后,那么就会使用转发技术,转发到JSP页面上,在页面上使用EL表达式把request中的数据取出,并显示。

猜你喜欢

转载自blog.csdn.net/xuruanshun/article/details/102664796
今日推荐