我们知道,HTTP协议是无状态的,也就是说每个请求都是独立的,无法记录上一次请求的状态。但HTTP协议中可以使用Cookie来完成会话跟踪。
在JavaWeb中,使用Session来完成会话跟踪,Session底层依赖Cookie技术。
一、Cookie
1、Cookie概述
Cookie是一个键值对组成的,随着服务器端的响应发送给客户端浏览器。浏览器会把Cookie保存起来,当下一次再访问服务器时会把Cookie一起发送给服务器。
这个作用就像你去超市购物时,第一次给你办张购物卡,这个购物卡中存储了你的个人信息,下次你再来超市购物时,超市会识别你的购物卡,就可以直接购物了。
Cookie是由服务器创建,然后通过响应发送给客户端浏览器的一个键值对。浏览器会保存Cookie,并且会标注出Cookie的来源(那个服务器的Cookie)。当浏览器向服务器发送请求时会把这个服务器发送的Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了。
2、Cookie规范
a、Cookie大小上限为4KB。
b、一个服务器最多在客户端浏览器保存20个Cookie(当然每个浏览器每个版本都有异同,如下图所示)
c、一个浏览器最多保存300个Cookie
上面的数据只是HTTP的Cookie规范,在今天,一下浏览器对规范扩展了一下。你可以由上图看到。
要注意的是,Cookie在浏览器之间不是共享的。也就是说你使用IE浏览器访问服务器时,服务器返回的Cookie发送给IE浏览器,然后由IE保存起来,当你在使用FireFox浏览器访问服务器时,不会把IE保存的Cookie发送给服务器。
3、Cookie和HTTP头
Cookie是HTTP请求和响应头在服务器和客户端传递的。
可以看到在发送请求时,会将Cookie包含在请求头中。
格式为Cookie:a=A;b=B;c=C。多个Cookie使用分号隔开
4、Cookie的生命
Cookie不只是有name和value,Cookie还有生命。Cookie的生命就是Cookie在浏览器的有效时间,可以通过setMaxAge
(int age)来设置Cookie的有效时间
a、cookie.setMaxAge(-1):Cookie的maxAge属性默认为-1,表示只在浏览器内存活。一旦关闭浏览器,那么Cookie就会消失。
b、cookie.setMaxAge(60*60):表示Cookie对象可存活一小时。当生命大于0时,浏览器会把Cookie保存到硬盘上,就算重启浏览器,Cookie也会存活一小时。
c、cookie.setMaxAge(0):Cookie的生命等于0是一个特殊值,它表示Cookie被作废。也就是说我们可以使用设置Cookie的生命等于0来删除某个存在于浏览器的Cookie。无论是在浏览器内存或者在客户端硬盘。
5、Cookie的路径
假如现在有Web应用A,向客户端发送了10个Cookie,这就说明客户端无论访问应用A的那个Servlet都会把这10个Cookie包含在请求中。但是我们也许只有某个AServlet需要读取请求中的Cookie,而其他的Servlet根本不需要获取请求中的Cookie。我们可以设置Cookie的path来指定浏览器再访问什么样的路径时,包含什么样的Cookie。
下面是客户端浏览器保存的2个Cookie的路径:
a:/cookietest;
b:/cookietest/servlet;
下面是浏览器请求的URL:
A:http://localhost:8080/cookietest/AServlet;
B:http://localhost:8080/cookietest/servlet/BServlet;
那么在请求A时,请求中会包含a
请求B时,请求中会包含a,b。
也就是说,请求路径如果包含了Cookie路径,那么会在请求中包含这个Cookie,否则请求中不会包含这个Cookie
使用Cookie.setPath("/path")来设置Cookie的路径。
如果没有设置Cookie的路径,那么Cookie的路径就是Cookie的默认路径。
Cookie的默认路径:访问serlvet的路径,从"/项目名称"开始,到最后一个"/"结束
例如:
访问的serlvet路径:/Project/a/b/hello
默认路径为:/Project/a/b
6、Cookie写入中文
Cookie的name和value都不能使用中文,如果希望在Cookie中使用中文,那么就需要对中文进行URL编码,然后把编码后的字符串放到Cookie中。可以像下面这样:
String name = URLEncoder.encode("姓名", "UTF-8");
String value = URLEncoder.encode("张三", "UTF-8");[使用URL编码]
Cookie c = new Cookie(name, value);[编码后的字符串保存到Cookie中]
c.setMaxAge(3600);
response.addCookie(c);
二、HttpSession
1、HttpSession概述:
HttpSession表示一次会话,我们可以把一个会话内需要共享的数据保存到Session对象中。
2、获取HttpSession对象
a、HttpSession request.getSession(); 如果当前会话已经存在session对象则返回这个session对象,否则创建Session对象并返回
b、HttpSession request.getSession(boolean):当传入true时,和getSession相同,当传入false时,如果当前会话存在session对象则返回,否则返回null。
3、HttpSession是域对象
Session的域方法:
a、void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性。
b、Object getAttribute(String name):用来获取session中的数据,当前在获取之前需要先去存储才行。
c、void removeAttribute(String name):用来移除HttpSession中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
3、Session的生命周期
创建:第一次调用request.getSession()时创建Session对象
销毁:
a、服务器异常关闭
b、Session超时
c、手动关闭:session.invalidate()
4、Session的实现
Session底层是依赖于Cookie的。
同一个客户端和服务端交互时,不需要每次都传回所有的Cookie值,而是只要传回一个ID,这个ID是客户端第一次访问服务器端生成的,而且每个客户端是唯一的。这样每个客户端就有了一个唯一的ID,客户端只要传回这个ID就行了,这个ID通常是NAME为JSESSIONID的一个Cookie。
当客户端再次访问服务器时,在请求中会带上sessionId,而服务器会通过sessionId找到对应的Session,而无需创建新的Session。
Session保存在服务器,而sessionId通过Cookie发送给浏览器,但这个Cookie的生命为-1,即只在浏览器内存中存在,当用户关闭浏览器时,这个Cookie就会消失。
保存在服务器端的Session对象会在Session有效时长中保存,一旦有效时长过期,则会被删除。这个时长在Tomcat中配置为30分钟,当然你也可以在web.xml中覆盖这个配置
<session-config>
<session-timeout>30</session-timeout>
</session-config>
5、session常用API
a、String getId():获取sessionId
b、 int getMaxInactiveInterval():获取session可以的最大不活动时间(秒),默认为30分钟。当session在30分钟内没有使用,那么Tomcat会在session池中移除这个session;
c、void setMaxInactiveInterval(int interval):设置session允许的最大不活动时间(秒),如果设置为1秒,那么只要session在1秒内不被使用,那么session就会被移除;
d、long getCreationTime():返回session的创建时间,返回值为当前时间的毫秒值;
e、long getLastAccessedTime():返回session的最后活动时间,返回值为当前时间的毫秒值;
f、void invalidate():让session失效!调用这个方法会被session失效,当session失效后,客户端再次请求,服务器会给客户端创建一个新的session,并在响应中给客户端新session的sessionId;
6、URL重写
我们知道session依赖Cookie,那么session为什么依赖Cookie呢?因为服务器需要在每次请求中获取sessionId,然后找到客户端的session对象。那么如果客户端浏览器关闭了Cookie呢?那么session是不是就会不存在了呢?
我们可以使用URL重写来解决这个问题。
使用response.encodeURL对每个请求的URL进行处理,这个方法会自动追加jsessionId参数。
<a href='<%=response.encodeURL("/Project/index.jsp") %>' >主页</a>
<form action='<%=response.encodeURL("/Project/index.jsp") %>' method="post">
<input type="submit" value="提交"/>
</form>
当我们点击超链接或者提交表单时,该方法会自动判断客户端是否支持Cookie。如果客户端支持Cookie,会将URL原封不动地输出来。如果客户端不支持Cookie,则会将用户Session的id重写到URL中。
当浏览器不支持Cookie时,上述代码提交的重写URL可能是这样的:
<a href="/Project/index.jsindex.jsp;jsessionid=0CCD096E7F8D97B0BE608AFDC3E1931E) >主页</a>
7、Session是如何基于Cookie来工作的
a、基于URL path Parameter,默认支持
b、基于Cookie,如果没有修改Context容器的Cookies标识,则默认也是支持的。
c、基于SSL,默认不支持,只有connector.getAttribute("SSLEnabled")为true时才支持(不知道是什么鬼)
①在a情况下,当浏览器不支持Cookie功能时,浏览器会将用户的SessionCookieName重写到用户请求的URL参数中,传递格式为/path/Servlet;name=value;name2=value2,其中SessionCookieName就是大家熟悉的"JSESSIONID"。
②如果客户端支持Cookie,则Tomcat仍然会解析Cookie中的SessionID,并会覆盖URL中的Session ID。
③c情况下,会根据javax.servlet.request.ssl_session属性值设置Session ID。