会话技术
基本概念: 指用户开一个浏览器,访问一个网站,只要不关闭该浏览器,不管该用户点击多少个超链接,访问多少资源,直到用户关闭浏览器,整个这个过程我们称为一次会话.
Cookie
Cookie是由W3C组织提出,最早由netscape社区发展的一种机制
- Cookie的流程:浏览器访问服务器,如果服务器需要记录该用户的状态,就使用response向浏览器发送一个Cookie,浏览器会把Cookie保存起来。当浏览器再次访问服务器的时候,浏览器会把请求的网址连同Cookie一同交给服务器。
Cookie API
Java中的javax.servlet.http.Cookie类用于创建一个Cookie
Cookie类的主要方法 | |||
---|---|---|---|
No. | 方法 | 类型 | 描述 |
1 | [Cookie](https://www.cnblogs.com/xdp-gacl/p/3803033.html#Cookie(java.lang.String, java.lang.String))(String name, String value) | 构造方法 | 实例化Cookie对象,传入cooke名称和cookie的值 |
2 | public String getName() | 普通方法 | 取得Cookie的名字 |
3 | public String getValue() | 普通方法 | 取得Cookie的值 |
4 | public void setValue(String newValue) | 普通方法 | 设置Cookie的值 |
5 | public void setMaxAge(int expiry) | 普通方法 | 设置Cookie的最大保存时间,即cookie的有效期,当服务器给浏览器回送一个cookie时,如果在服务器端没有调用setMaxAge方法设置cookie的有效期,那么cookie的有效期只在一次会话过程中有效,用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一次会话,当用户关闭浏览器,会话就结束了,此时cookie就会失效,如果在服务器端使用setMaxAge方法设置了cookie的有效期,比如设置了30分钟,那么当服务器把cookie发送给浏览器时,此时cookie就会在客户端的硬盘上存储30分钟,在30分钟内,即使浏览器关了,cookie依然存在,在30分钟内,打开浏览器访问服务器时,浏览器都会把cookie一起带上,这样就可以在服务器端获取到客户端浏览器传递过来的cookie里面的信息了,这就是cookie设置maxAge和不设置maxAge的区别,不设置maxAge,那么cookie就只在一次会话中有效,一旦用户关闭了浏览器,那么cookie就没有了,那么浏览器是怎么做到这一点的呢,我们启动一个浏览器,就相当于启动一个应用程序,而服务器回送的cookie首先是存在浏览器的缓存中的,当浏览器关闭时,浏览器的缓存自然就没有了,所以存储在缓存中的cookie自然就被清掉了,而如果设置了cookie的有效期,那么浏览器在关闭时,就会把缓存中的cookie写到硬盘上存储起来,这样cookie就能够一直存在了。 |
6 | public int getMaxAge() | 普通方法 | 获取Cookies的有效期 |
7 | public void setPath(String uri) | 普通方法 | 设置cookie的有效路径,比如把cookie的有效路径设置为”/xdp”,那么浏览器访问”xdp”目录下的web资源时,都会带上cookie,再比如把cookie的有效路径设置为”/xdp/gacl”,那么浏览器只有在访问”xdp”目录下的”gacl”这个目录里面的web资源时才会带上cookie一起访问,而当访问”xdp”目录下的web资源时,浏览器是不带cookie的 |
8 | public String getPath() | 普通方法 | 获取cookie的有效路径 |
9 | public void setDomain(String pattern) | 普通方法 | 设置cookie的有效域 |
10 | public String getDomain() | 普通方法 | 获取cookie的有效域 |
response接口也中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。 同样,request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。
- Cookie类用于创建一个Cookie对象
- response接口中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段
- request接口中定义了一个getCookies方法,它用于获取客户端提交的Cookie
简单使用Cookie
- 创建Cookie对象,发送Cookie给浏览器、
1 | //设置response的编码 |
- 保存中文
1 | response.setContentType("text/html;charset=UTF-8"); |
- 我们发现Cookie保存在硬盘的中文数据是经过编码的,那么我们在取出Cookie的时候要对中文数据进行解码
1 | Cookie[] cookies = request.getCookies(); |
Cookie不可跨域名性
Cookie具有不可跨域名性。浏览器判断一个网站是否能操作另一个网站的Cookie的依据是域名。所以一般来说,当我访问baidu的时候,浏览器只会把baidu颁发的Cookie带过去,而不会带上google的Cookie。
Cookie的有效期
Cookie的有效期是通过setMaxAge()来设置的。
- 如果MaxAge为正数,浏览器会把Cookie写到硬盘中,只要还在MaxAge秒之前,登陆网站时该Cookie就有效【不论关闭了浏览器还是电脑】
- 如果MaxAge为负数,Cookie是临时性的,仅在本浏览器内有效,关闭浏览器Cookie就失效了,Cookie不会写到硬盘中。Cookie默认值就是-1。这也就为什么在我第一个例子中,如果我没设置Cookie的有效期,在硬盘中就找不到对应的文件。
- 如果MaxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie对应的方法,把MaxAge设置为0等同于删除Cookie
Cookie的修改和删除
- 上面我们已经知道了Cookie机制没有提供删除Cookie的方法。其实细心点我们可以发现,Cookie机制也没有提供修改Cookie的方法。那么我们怎么修改Cookie的值呢?
- Cookie存储的方式类似于Map集合
- Cookie的名称相同,通过response添加到浏览器中,会覆盖原来的Cookie。
- 注意:删除,修改Cookie时,新建的Cookie除了value、maxAge之外的所有属性都要与原Cookie相同。否则浏览器将视为不同的Cookie,不予覆盖,导致删除修改失败!
删除Cookie示例:
1 | public class CookieDemo02 extends HttpServlet { |
Cookie的域名
Cookie的domain属性决定运行访问Cookie的域名。domain的值规定为“.域名”
- Cookie的隐私安全机制决定Cookie是不可跨域名的。也就是说www.baidu.com和www.google.com之间的Cookie是互不交接的。**即使是同一级域名,不同二级域名也不能交接**,也就是说:www.goole.com和www.image.goole.com的Cookie也不能访问
Cookie的安全属性
- HTTP协议不仅仅是无状态的,而且是不安全的!如果不希望Cookie在非安全协议中传输,可以设置Cookie的secure属性为true,浏览器只会在HTTPS和SSL等安全协议中传输该Cookie。
- 当然了,设置secure属性不会将Cookie的内容加密。如果想要保证安全,最好使用md5算法加密。
Session
Session 是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录在服务器,这就是Session
Session和Cookie的区别
- Cookie是把用户的数据写给用户的浏览器。
- Session技术把用户的数据写到用户独占的session中。
- Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
- Session可以存储对象,Cookie只能存储字符串。
Session的生命周期和有效期
- Session在用户第一次访问服务器Servlet,jsp等动态资源就会被自动创建,Session对象保存在内存里。
- 如果访问HTML,IMAGE等静态资源Session不会被创建。
- Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,无论是否对Session进行读写,服务器都会认为Session活跃了一次。
- 由于会有越来越多的用户访问服务器,因此Session也会越来越多。为了防止内存溢出,服务器会把长时间没有活跃的Session从内存中删除,这个时间也就是Session的超时时间。
Session创建和销毁
服务器创建session出来后,会把session的id号,以cookie的形式回写给客户机,这样,只要客户机的浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现客户机浏览器带session id过来了,就会使用内存中与之对应的session为之服务。
创建:
1 | //使用request对象的getSession()获取session,如果session不存在则创建一个 |
销毁:
session对象默认30分钟没有使用,则服务器会自动销毁session,在web.xml文件中可以手工配置session的失效时间
1 |
|
- 在tomcat/conf/web.xml文件中设置,时间值为20分钟,所有的WEB应用都有效
- 在单个的web.xml文件中设置,对单个web应用有效,如果有冲突,以自己的web应用为准。
当需要在程序中手动设置Session失效时,可以手工调用session.invalidate方法,摧毁session。
1 | HttpSession session = request.getSession(); |
Session应用
1、表单重复提交
- 网络延迟
- 表单提交后,用户多次刷新
- 表单提交后,点击浏览器“后退”按钮回退到表单页面后再次提交
方法一:只能解决在网络延迟的情况下防止用户多次提交
1 | public class DoFormServlet extends HttpServlet { |
方法二:利用Session
具体的做法:在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
在下列情况下,服务器程序将拒绝处理用户提交的表单请求:
- 存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
- 当前用户的Session中不存在Token(令牌)。
- 用户提交的表单数据中没有Token(令牌)。
创建Token:
1 | public class FormServlet extends HttpServlet { |
在jsp文件中使用隐藏域来存储Token:
1 | <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> |
处理表单请求:
1 | public class DoFormServlet extends HttpServlet { |