Servlet学习笔记(四)
一、会话技术Cookie、session
1. 什么是会话技术?
指用户打开一个浏览器,访问一个网站,只要不关闭该浏览器,不管该用户点击多少个超链接,访问多少资源,直到用户关闭浏览器,整个这个过程我们称为一次会话,在一次会话中可以有多次请求,可以共享数据
会话跟踪技术有Cookie和Session,Cookie技术是先出现的
2. 会话技术有什么用?
我们在登录网站时候,有的会提示是否自动登录,这样得到下次访问就可以直接不用登录了,这就是使用了会话技术的
3. Cookie
3.1 什么是Cookie?
Cookie是由W3C组织提出,最早由netscape社区发展的一种机制
- 我也之间交互是通过HTTP协议传输数据的,但是HTTP协议是无状态的,一旦提交完数据,浏览器和服务器的连接就会被关闭,再次连接时候又是一个新的连接,服务器无法直到是否浏览器上次来过了。多以W3C提出了:给每一个用户发一个通行证,无论谁访问都携带通行证,这样服务器就可以直到用户的信息了
3.2 使用Cookie
Cookie是基于响应头set-cookie和请求头cookie实现的
**浏览器对于单个cookie 的大小有限制(4kb) **
添加Cookie
//设置response的编码
response.setContentType("text/html;charset=utf-8");
//创建一个Cookie对象
Cookie cookie = new Cookie("username", "linzeliang");
//将cookie的maxAge过期时间设置为1小时
cookie.setMaxAge(60 * 60)
//将cookie对象添加到response对象,发送cookie
response.addCookie(cookie);
获取Cookie
//通过request获取浏览器发送来的Cookie
Cookie[] cookies = request.getCookies();
//遍历cookies,获取每一个cookie
for (Cookie cookie : cookies) {
System.out.println(cookie.getValue());
}
Cookie工作流程:
- 浏览器访问服务器,如果服务器需要记录该用户的状态,就使用response向浏览器发送一个Cookie,浏览器会把Cookie保存起来。当浏览器再次访问服务器的时候,浏览器会把请求的网址连同Cookie一同交给服务器。
Cookie API:
- Cookie类用于创建一个Cookie对象
- response接口中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段
- request接口中定义了一个getCookies方法,它用于获取客户端提交的Cookie
常用的Cookie方法:
- public Cookie(String name,String value)
- setValue与getValue方法
- setMaxAge与getMaxAge方法
- setPath与getPath方法
- setDomain与getDomain方法
- getName方法
3.2 可以创建多个Cookie吗?
可以的。可以同通过调用多次addCookie方法来发送多个cookie,浏览器就也会收到多个Cookie
3.3 Cookie在浏览器保存多久时间?
- 在默认情况下,只要关闭浏览器,Cookie就会被销毁
- 如果要持久化储存,即存储到硬盘上,则需要在服务器设置
response.setMaxAge(int seconds)
:- 如果seconds为整数,则数字就是代表存储多少秒
- 如果为负数(也就是默认的-1),代表Cookie是临时性的,关闭浏览器立即销毁该Cookie
- 如果为0,代表删除Cookie信息,即下一次浏览器向客户端请求时,不带该cookie,因为已经删除了
3.4 Cookie保存中文
-
在Tomcat8之前,Cookie不能保存中文,需要将中文进行URL编码
Cookie cookie = new Cookie("username", URLEncoder.encode("名字", "UTF-8"));
//同样,既让是通过URL编码发送到了浏览器,浏览器也是按照URL编码存储到硬盘中的,我们在获取cookie时候还需要将其解码
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
String name = cookie.getValue();
//URLDecoder解码
String value = URLDecoder.decode(name, "UTF-8");
System.out.println(value);
} 在Tomcat8及其之后,cookie支持中文数据,但是还是不支持特殊字符。为了容易维护,建议都使用URL编码进行存储和解析
3.5 Cookie的不可跨域名性
在访问Servlet的时候浏览器是不是把所有的Cookie都带过去给服务器,会不会修改了别的网站的Cookie?是不会的的,Cookie具有不可跨域名性。浏览器判断一个网站是否能操作另一个网站的Cookie的依据是域名。所以一般来说,当我访问baidu的时候,浏览器只会把baidu颁发的Cookie带过去,而不会带上google的Cookie
3.6 修改、删除Cookie的值
Cookie机制也没有提供修改Cookie的方法,那么我们怎么修改Cookie的值呢?
我们可以通过Cookie的名字相同。通过response来添加到浏览器中,这样就会覆盖之前的Cookie了
Cookie删除即将色图Max Age修改为0即可
注意:删除,修改Cookie时,新建的Cookie除了value、maxAge之外的所有属性都要与原Cookie相同。否则浏览器将视为不同的Cookie,不予覆盖,导致删除修改失败!
3.7 Cookie的共享
正常的cookie只能在一个应用*享,即一个cookie只能由创建它的应用获得。
-
默认情况下在一个tomcat服务器中,部署了多个web项目,那么在这些web项目中cookie不能共享,如果需要共享,只需要设置
setPath("/")
即可,因为默认的就是当前的虚拟目录("/"指的是相对路径,本例中即是应用部署路径,tomcat/webapp)设置cookie.setPath("/webapp_a/jsp")或者cookie.setPath("/webapp_a/jsp/")的时候,只有在webapp_a/jsp下面可以获得cookie,在webapp_a下面但是在jsp文件夹外的都不能获得cookie
-
不同的tomcat服务器间cookie共享问题
Cookie的domain属性决定运行访问Cookie的域名。domain的值规定为“.域名”
Cookie的隐私安全机制决定Cookie是不可跨域名的。也就是说www.baidu.com和www.google.com之间的Cookie是互不交接的。即使是同一级域名,不同二级域名也不能交接,也就是说:www.goole.com和www.image.goole.com的Cookie也不能访问
-
如果现在我希望一级域名相同的网页Cookie之间可以相互访问。也就是说www.img.linzeliang.com可以获取到www.linzeliang.com的Cookie就需要使用到domain方法
Cookie cookie = new Cookie("username", "linzeliang");
cookie.setMaxAge(60 * 60);
cookie.setDomain(".linzeliang.com");
response.addCookie(cookie);
-
setPath()和setDomain()区别:
- Cookie中的setDomain()主要用来在两个不同名称但是后缀相同的网站地址上(不同主机),这样两个网站就能使用同一个cookie了
- setPath()主要用来确定什么后缀下能够使用这个cookie,即地址栏上面的地址的约束
3.8 Cookie的安全属性
HTTP协议不仅是无状态,而且也不安全的,因为是明文传输的,如果不希望Cookie在非安全协议中传输,那么可以设置Cookie的secure属性为true,这样浏览器只会在HTTPS和SSL等安全协议中传输该Cookie
3.9 Cookie的应用
显示用户的上次访问时间
如果用户第一次登录,那么就记录下时间,发送Cookie,并且在页面打印时第一次登录;如果不是第一次,就显示上一次是什么时候登录的
-
代码如下:
response.setContentType("text/html;charset=utf-8");
//获取浏览器发送的所以cookie
Cookie[] cookies = request.getCookies();
//用来判断是否访问过了
boolean flag = false;
if (cookies != null && cookies.length != 0) {
for (Cookie cookie : cookies) {
if ("lastTime".equals(cookie.getName())) {
//标记访问过了
flag = true;
//获取上一次登录记录
String dateValue = cookie.getValue();
dateValue = URLDecoder.decode(dateValue, "utf-8");
PrintWriter pw = response.getWriter();
//显示到浏览器中
pw.write("<center><h1>您好,您上一次登录是在" + dateValue + "</h1></center>"); //获取这次访问的时间记录
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
str_date = URLEncoder.encode(str_date, "utf-8");
cookie.setValue(str_date);
cookie.setMaxAge(60*60*24*30);
//发送新的Cookie,覆盖掉原来的
response.addCookie(cookie); break;
}
}
}
//第一次访问
if (cookies == null || cookies.length == 0 || flag == false) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str_date = sdf.format(date);
//要用URL编码,否则空格浏览器不能解析
str_date = URLEncoder.encode(str_date, "utf-8");
Cookie cookie = new Cookie("lastTime", str_date);
cookie.setMaxAge(60*60*24*30);
response.addCookie(cookie);
}
4.Session
4.1什么是Session?
Session 服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中,对应的是HttpSession对象
Session 是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录在服务器,这就是Session
如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中建立了一份“客户明细表”
有了Cookie为什么还要session?
Session比Cookie使用方便,Session可以解决Cookie解决不了的事情(Session可以存储对象,Cookie只能存储字符串)
4.2 使用Session
获取Session对象
//获取session对象
HttpSession session = request.getSession();
//设置session属性
session.setAttribute("username", "linzeliang");
从其他的Servlet访问Session对象设置的属性
HttpSession session = request.getSession();
String value = (String) session.getAttribute("username");
System.out.println(value);
//打印的结果就是linzeliang
一般来讲,当我们要存进的是用户级别的数据就用Session,那什么是用户级别呢?只要浏览器不关闭,希望数据还在,就使用Session来保存。
Session API
- long getCreationTime();【获取Session被创建时间】
- String getId();【获取Session的id】
- long getLastAccessedTime();【返回Session最后活跃的时间】
- ServletContext getServletContext();【获取ServletContext对象】
- void setMaxInactiveInterval(int var1);【设置Session超时时间】
- int getMaxInactiveInterval();【获取Session超时时间】
- Object getAttribute(String var1);【获取Session属性】
- Enumeration getAttributeNames();【获取Session所有的属性名】
- void setAttribute(String var1, Object var2);【设置Session属性】
- void removeAttribute(String var1);【移除Session属性】
- void invalidate();【销毁该Session】
- boolean isNew();【该Session是否为新的】
4.3 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
默认情况下不是(虽然也会自动发送JSESSIONID,但是setMaxAge是默认的,一关闭浏览器Cookie就没了,所以无法通过ID找到原来的session,所以不相同)
-
如果需要相同,那么可以创建Cookie,键为JSESSIONID。设置setMaxAge
Cookie c = new Cookie("JSESSIONID", session.getId());
c.setMaxAge(60 * 60);
response.addCookie(c);
4.4 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
- 不是同一个,但是为了保证数据不丢失,tomcat会自动完成如下操作:
- session的钝化:
- 在服务器正常关闭以前,将session对象序列化到硬盘上
- session的活化:
- 服务器启动后,将session文件转化为session对象(虽然对象不是同一个,但是数据确是一样的)
- session的钝化:
4.3 session什么时候被销毁?
服务器被关闭
session对象调用invalidate()方法,让session中的多有属性失效,常常用于安全退出
-
或者等待30分钟没有活跃就会被销毁(用于用户多,防止内存溢出),但是30分钟我们可以在web.xml配置文件中修改(默认是30分钟,如果tomcat的web.xml和自己的web应用的web.xml冲突,那么以自己的为准)
<session-config>
<session-timeout>60(自定义时间,默认30)</session-timeout>
</session-config> -
通过setMaxInactiveInterval()方法设置
//设置Session最长超时时间为60秒,这里的单位是秒
session.setMaxInactiveInterval(60);
System.out.println(session.getMaxInactiveInterval());
4.4 Session和Cookie的有效期不同
- session:
- session的周期是指多长时间内没有访问
- 如果希望session的某个属性失效,可以使用removeAttribute()方法
- Cookie:
- Cookie的周期就是 从这个Cookie到达用户内存中开始计时,不管期间有没有访问过
4.5 Cookie被禁用怎么办?
由于Session是基于Cookie运行的,如果禁用了Cookie,session要怎么办呢?
- 我们可以对URL进行重写,HttpServletResponse又encodeURL(String url)和encodeRedirectURL(String url)tring url)和encodeRedirectURL(String url),重写完成后,使用sendRedirect来重定向,这样JSESSIONID在URL中被带过去了
- URL地址重写的原理:将Session的id信息重写到URL地址中。服务器解析重写后URL,获取Session的id。这样一来,即使浏览器禁用掉了Cookie,但Session的id通过服务器端传递,还是可以使用Session来记录用户的状态
encodeURL(java.lang.String url)
该方法的实现机制为:
- 先判断当前的 Web 组件是否启用 Session,如果没有启用 Session,直接返回参数 url。
- 再判断客户端浏览器是否支持 Cookie,如果支持 Cookie,直接返回参数 url;如果不支持 Cookie,就在参数 url 中加入 Session ID 信息,然后返回修改后的 url。
4.5 Session禁用Cookie(让Session不依赖Cookie)
Java Web规范支持通过配置禁用Cookie,禁用自己项目的Cookie,在META-INF文件夹下的context.xml文件中修改(没有则创建)
如果要禁用全部web应用的Cookie,在conf/context.xml
注意:该配置只是让服务器不能自动维护名为jsessionid的Cookie,并不能阻止Cookie的读写
4.8 Session的特点
- session用于存储一次会话的多次请求的数据,存储在服务器端
- session可以存储任意数据类型,任意大小的数据
4.9 Session和Cookie的区别
从存储方式上比较
Cookie只能存储字符串,如果要存储非ASCII字符串还要对其编码
session大小没有限制,cookie最大为4kb(4095-4097B,不同浏览器不一样,所以一般认为最大不超过4095B)
session存储数据安全,cookie存储数据相对来说不安全
Session可以存储任何类型的数据,可以把Session看成是一个容器
从隐私安全上比较
- Cookie存储在浏览器中,对客户端是可见的。信息容易泄露出去。如果使用Cookie,最好将Cookie加密
- Session存储在服务器上,对客户端是透明的。不存在敏感信息泄露问题。
从有效期上比较
- Cookie保存在硬盘中,只需要设置maxAge属性为比较大的正整数,即使关闭浏览器,Cookie还是存在的
- Session的保存在服务器中,设置maxInactiveInterval属性值来确定Session的有效期。并且Session依赖于名为JSESSIONID的Cookie,该Cookie默认的maxAge属性为-1。如果关闭了浏览器,该Session虽然没有从服务器中消亡,但也就失效了。
从对服务器的负担比较
- Session是保存在服务器的,每个用户都会产生一个Session,如果是并发访问的用户非常多,是不能使用Session的,Session会消耗大量的内存。
- Cookie是保存在客户端的。不占用服务器的资源。像baidu、Sina这样的大型网站,一般都是使用Cookie来进行会话跟踪。
从浏览器的支持上比较
- 如果浏览器禁用了Cookie,那么Cookie是无用的了
- 如果浏览器禁用了Cookie,Session可以通过URL地址重写来进行会话跟踪。
从跨域名上比较
- Cookie可以设置domain属性来实现跨域名
- Session只在当前的域名内有效,不可夸域名