前言
为了实现某一个功能,浏览器和服务器之间可能会产生多次的请求和响应
从打开浏览器访问服务器开始,到访问服务器结束关闭浏览器为止,这前间产生的多次请求和响应加在一起就称之为浏览器和服务器之间的一次会话
思考:在一次会话中往往会产生一些数据,那么这些数据是如何保存起来的呢?
这就是今天这边文章要讲到的cookie和session技术。
Cookie
储存在用户本地终端上的数据
我们知道网页之间的交互是通过无状态浏览器HTTP传输数据的,也就是说一但数据提交成功,浏览器和服务器的连接就会关闭,再次交互的时候就需要建立新的连接,这样就造成服务器无法确认用户的信息。
于是一个叫W3C的组织提出给每一个用户颁发一个通行证,无论谁访问的时候都需要携带这个通行证,这样服务器就可以从通行证上确认用户的信息
Cookie工作原理
- Cookie是通过Set-Cookie和Cookie请求头将会话中产生的数据保存在客户端,是客户端的数据
- 客户端向服务器发送请求,服务器获取需要保存的数据,通过Set-Cookie响应头发送到浏览器,浏览器就会以Cookie的方式保存在浏览器的内部
- 当客户端再次发送请求访问浏览器,服务器可以通过Cookie请求头获取上次发送给浏览器的Cookie消息,通过这种方式可以保存会话中产生的数据
- 由于Cookie技术是将会话中产生的数据保存在客户端,每个客户端各自持有自己的数据,因此不会造成混乱
Cookie的API
方法 | 说明 |
---|---|
new Cookie() | 创建一个Cookie对象 |
addCookie() | 将Cookie添加到Request域中 |
getCookies() | 获得请求中所有Cookie对象组成的数组 |
getName() | 获取Cookie的名称 |
getValue() | 获取Cookie的值 |
setValue() | 设置Cookie的值 |
setMaxAge() | 设置Cookie的最大生存时间 |
setPath() | 设置Cookie的path |
Cookie入门
-
创建Cookie对象,发送给浏览器
public class Demo11 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置response的编码 resp.setContentType("text/html;charset=UTF-8"); //创建一个Cookie对象 Cookie cookie = new Cookie("name", "juzi"); //发送给浏览器 resp.addCookie(cookie); resp.getWriter().write("桔子"); } }
-
输出结果
我们可以看到Response Headers中包含Set-Cookie头部,而Request Headers中包含了Cookie头部。name和value正是上述代码设置的
Cookie属性
属性 | 说明 |
---|---|
NAME=VALUE | 键值对,可以设置要保存的 Key/Value,注意这里的 NAME 不能和其他属性项的名字一样 |
Expires | 存活时间,在某一个时间Cookie就会失效 |
Domain | 生成该 Cookie 的域名,如 domain=“www.baidu.com” |
path | 表示是在当前的哪个路径下生成的,如 path=/Demo1 |
Secure | 设置了这个属性,那么只会在 SSH 连接时才会回传该 |
-
Expires
-
Expires属性用于设置cookie的最大生存时间,也就是cookie什么时候失效
-
cookie中的maxAge用来表示该属性,单位为秒
-
cookie中通过getMaxAge()和setMaxAge()来读写该属性,它有三种值
-
当maxAge为正数时,则表示Cookie会在maxAge秒后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的cookie文件中,无论客户关闭浏览器还是电脑,只要还在maxAge之前,登录网站时,该Cookie就依然有效
//创建Cookie对象,指定名称和值 Cookie cookie = new Cookie("name", "juzi"); //设置cookie最大存活时间1000秒 cookie.setMaxAge(1000); resp.addCookie(cookie);
-
当maxAge为0时,则表示Cookie的存活时间为0,也就是说删除了该Cookie。因为Cookie机制没有提供删除cookie的方法,因此通过设置maxAge时间为0也就间接的实现了删除cookie的效果。失效的cookie会被浏览器从cookie文件中或内存中删除
//创建Cookie对象,指定名称和值 Cookie cookie = new Cookie("name", "juzi"); //maxAge为0,间接删除该cookie cookie.setMaxAge(0); resp.addCookie(cookie);
-
当maxAge为负数时,则表示Cookie是临时的,只在本浏览器窗口或本浏览器打开的子窗口有效,关闭窗口cookie立即失效。也就不会被持久化,不会被写道cookie文件中,Cookie默认的maxAge时间为-1
//创建Cookie对象,指定名称和值 Cookie cookie = new Cookie("name", "juzi"); //maxAge为负数,表示一个临时的cookie cookie.setMaxAge(-1); resp.addCookie(cookie);
-
-
-
Domain
-
Domin属性表示访问此cookie的域名,这个cookie在哪个域是有效的,也就是决定再向该域发送请求时是否携带该cookie
-
Domain的设置是对子域生效的,参数必须以点(“.”)开始
-
如果Domain设置为 .a.com (顶级域名), 则 b.a.com 和 c.a.com (二级域名)均可使用此Cookie,但是如果设置为 b.a.com 则 c.a.com 不可使用此cookie
总结
顶级域名只能获取到Domain为顶级域名的cookie,其他Domain设置为二级域名的无法获取,二级域名能读取设置了Domain为顶级域名或者自身的cookie,不能读取其他二级域名Domain的cookie。所有要想cookie在多个二级域名中共享,需要设置Domain为顶级域名,这样就可以在所有二级域名里面获取到这个cookie的值了
-
-
path
-
path属性决定允许访问此cookie的页面路径,和Domain类似,也对子路径生效
-
在Demo11中设置cookie的path属性为 /Demo11
//创建Cookie对象,指定名称和值 Cookie cookie = new Cookie("name", "juzi"); cookie.setPath("/Demo11"); resp.addCookie(cookie);
-
测试Demo12中是否携带了此cookie
可以看到没有携带新创建的cookie
-
测试Demo11中是否携带了此cookie
可以看到浏览器携带上了新创建的cookie
-
-
Secure
- Secure为Cookie的安全属性,若设置为true,则浏览器只会在HTTPS和SSL等安全协议中传输此Cookie,不会在不安全的HTTP协议中传输此Cookie
Cookie细节(保存中文)
-
上面我们创建的cookie保存的都是英文,如果我们保存的是中文呢?
//省略部分代码。。。 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置response的编码 resp.setContentType("text/html;charset=UTF-8"); //创建Cookie对象,指定名称和值 Cookie cookie = new Cookie("name", "桔子"); resp.addCookie(cookie);
-
测试访问Demo11
我们可以看到cookie的值乱码了,这是为什么?
因为中文属于Unicode字符,英文属于ASCII字符,中文占四个字符,英文占2个字符,所以就乱码了啊
-
解决:我们可以对Unicode字符进行编码即可
//经过URLEncoding编码 Cookie cookie = new Cookie("name", URLEncoder.encode("桔子","UTF-8"));
-
再次测试访问Demo11
我们看到cookie的值不是乱码,显示的是我们编码后的字体
-
当我们想要取出cookie的值时,只需要在相应的解码即可
Cookie[] cookies = req.getCookies(); for (int i = 0; i < cookies.length; i++) { String name = cookies[i].getName(); //URLDecoding解码 String value = URLDecoder.decode(cookies[i].getValue(), "UTF-8"); resp.getWriter().write(name + "-----" + value); }
-
再次测试访问Demo11
Session
Session 是另一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。用户使用浏览器访问服务器的时候,服务器把用户的信息以某种形式记录在服务器,这就是Session
Session工作原理
- Session是将会话中产生的数据保存在服务端,是服务端的技术
- 浏览器第一次发送请求需要保存数据时,服务器获取到需要保存的数据,在服务器内部检查有没有为当前浏览器服务的session,如果有就直接拿过来用,如果没有session就创建一个新的session拿过来用。接着将数据保存在Session中,做出响应。
- 当浏览器再去访问服务器时,服务器可以从session中获取到之前为当前浏览器保存的数据,通过这种方式,也可以来保存会话中产生的数据。
Session的API
方法 | 说明 |
---|---|
getSession() | 创建一个Session对象 |
getAttribute() | 获取Session的属性 |
setAttribute() | 设置Session的属性 |
removeAttribute() | 移除Session对象 |
getCreationTime() | 获取Session对象被创建时间 |
getId() | 获取Session对象Id |
getMaxInactiveInterval() | 获取Session超时时间 |
setMaxInactiveInterval() | 设置Session超时时间 |
invalidate() | 立即销毁Session对象 |
Session入门
Session也是一个域对象,有着和request和ServletContext类似的方法
Session作为一种记录浏览器状态的机制,只要Session对象没有被销毁,那么Servlet之间就能通过Session对象实现通讯
-
测试代码,Demo13中设置Session的属性
/** * 测试Session */ public class Demo13 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //创建Session对象 HttpSession session = req.getSession(); //获取Session属性 session.setAttribute("session","测试来了。。。"); } }
-
Demo14中获取到Session
//省略部分代码。。。 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取到从Demo13的Session存进去的值 HttpSession session = req.getSession(); String value = (String) session.getAttribute("session"); System.out.println(value); }
-
先访问Demo13,后访问Demo14,输出结果
成功拿到我们之前设置的Session对象的属性值
Session生命周期
- 当客户端浏览器第一次访问服务器时,服务器默认为每个浏览器创建不同的Session对象。我们可以使用request.getSession()方法来获得Session对象。
- 当第一次执行 request.getSession()时,有session对象就返回创建的session,没有session就创建session对象。后续的request.getSession()只能获取已创建的session。
- 为了防止内存溢出,服务器会把长时间没有活跃的Session从内存中删除,这个时间也就是Session的超时时间。超时时间默认是30分钟
- 如果服务器正常关闭,session将会以文件的形式保存在服务器的work目录下,这个过程称之为session的钝化。
- 当服务器再次启动时,钝化着的session还可以再恢复回来,这个过程称之为session的活化!
Session实现原理
- 我们第一次访问Demo13,服务器会创建一个session对象(session本身是一个map集合),并且存入服务器的session集合中,也就是根据session的Id即可取到对应session的引用。
- 客户端则接收到服务器发送的一个名为JESSIONID的Cookie,它的值就是Session的id值。JESSIONID==request.getSession().getId()
- 简单的说:Session 之所以可以识别不同的用户,依靠的就是Cookie
- 该Cookie是服务器自动发送给客户端的,仅当前浏览器可以使用
- 只要客户端存在这个JESSIONID,不管请求那个Servlet,都可以拿到同一个Session,因此Session就可以给不同的请求存储数据。
Cookie和Session的区别
-
存储方式
- Cookie只能存储字符串,如果非要存储ASCII字符需要对其进行编码
- Session可以存储任何类型的数据,可以把它看成一个容器
-
隐私安全
- Cookie存储在浏览器,对客户端是可见的,可以对Cookie进行加密处理
- Session存储在服务器,对客户端不可见,不存在敏感信息泄露问题
-
有效期
- Cookie保存在硬盘,只需要设置maxAge的值为比较大的正整数,即使关闭浏览器,Cookie也是存在的
- Session保存在服务器,设置maxInactiveInterval属性值来确定Session的有效期。并且Session依赖于名为JSESSIONID的Cookie,该Cookie默认的maxAge属性为-1。如果关闭了浏览器,该Session虽然没有从服务器中消亡,但也就失效了。
-
负担
- Cookie是保存在客户端的。不占用服务器的资源。像baidu、Sina这样的大型网站,一般都是使用Cookie来进行会话跟踪。
- Session是保存在服务器的,每个用户都会产生一个Session,如果是并发访问的用户非常多,是不能使用Session的,Session会消耗大量的内存。
-
浏览器的支持
- 如果浏览器禁用了Cookie,那么Cookie是无用的
- 如果浏览器禁用了Cookie,Session可以通过URL地址重写来进行会话跟踪。
-
跨域名
- Cookie可以设置domain属性来实现跨域名
- Session只在当前的域名内有效,不能跨域名
这篇文章主要介绍了会话管理的Cookie和Session,以及他们的常用api、原理和区别等,因为本人还是一枚正在路上的菜鸟,不免会有错误之处还望大家及时指正,如果对您有所帮助,别忘了点赞,再看噢~~~