1.会话技术
1.1会话技术概述
会话可简单理解为:用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
1.2 会话技术的分类
(1)cookie:
Cookie是客户端技术,翻译成中文是小甜点。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie就是一个键和一个值构成的,随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了。
(2)session:
Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。
2.cookie
2.1 cookie概述
Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,对于JSP而言也可以直接写入jsessionid,这样服务器可以知道该用户是否合法用户以及是否需要重新登录等,服务器可以设置或读取Cookies中包含信息,借此维护用户跟服务器会话中的状态。
2.2 cookie与Http协议
(1)cookie与http协议关系
Cookie是Http协议制定的,并不是Java语言独有的,PHT、.NET中也使用了cookie技术,因此只要是和HTTP协议相关,那么就可以使用cookie技术。
cookie是服务器创建的一个键值对,并保存在浏览器端。在服务器端先创建cookie,如 Cookie cookie=newCookie(String name,String value),其中Cookie可以在javaeeAPI中查到的,详情可参考java_ee API。然后再通过response对象将cookie信息作为响应头发送到浏览器端。我们可以通过抓包工具查看响应信息,可以发现cookie是基于一个Set-Cookie响应头工作的,由于Set-Cookie响应头可以有多个,所以我们可以通过response.addHeader(Stringname,String value)方法发送Set-Cookie响应头,例如,有两个cookie,分别为one=aaa,two=bbb,其中one、two是cookie的名称,aaa、bbb是cookie的值。发送响应头如下所示:
response.addHeader(“Set-Cookie”,”one=aaa”);
response.addHeader(“Set-Cookie”,”two=bbb”);
当浏览器再次访问服务器时,会将cookie送还给服务器。浏览器通过Cookie请求头传递过去,请求头Cookie与响应头Set-Cookie有区别,多个cookie对应多个Set-Cookie响应头,但是只对应一个Cookie请求头,格式为:Cookie:one=aaa; two=bbb。即多个cookie之间用分号和空格隔开。
需要注意的是:cookie是不能跨浏览器的。例如,张三首先使用IE浏览器访问服务器,服务器发送了一个cookie,这个cookie只会保存在IE浏览器,如果再使用火狐浏览器访问服务器,服务器会再发送一个cookie个火狐浏览器,在火狐浏览器中不能获取IE浏览器中的cookie,同理IE浏览器也获取不到火狐浏览器中的cookie。
(2)http协议规定
Http协议对Cookie做了一些规定,如下所示:
a. 一个Cookie的大小,最大为4KB;
b. 一个服务器最多向一个浏览器保存20个Cookie;
c. 一个浏览器最多可以保存300个Cookie。
2.3 cookie常用方法
javax.servlet.http.Cookie类用于创建一个Cookie,response接口也中定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。 同样,request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。
构造方法:
public Cookie(String name, String value):构造带指定名称和值的 cookie。
成员方法:
public String getName():返回 cookie 的名称
public String getValue():返回 cookie 的值。
public void setMaxAge(int expiry):设置 cookie 的最大生存时间,以秒为单位
public void setPath(String uri):指定客户端应该返回 cookie 的路径。
第一次请求和响应信息:
第二次请求与响应信息:
2.4 cookie的持久化
如果创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用Cookie类的setMaxAge方法,并给出一个以秒为单位的时间。
(1)cookie.setMaxAge(-1):cookie的maxAge属性的默认值就是-1,表示只在浏览器内存中存活。一旦关闭浏览器窗口,那么cookie就会消失。
(2)cookie.setMaxAge(60*60):表示cookie对象可存活1小时。当生命大于0时,浏览器会把Cookie保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie也会存活1小时;
(3)cookie.setMaxAge(0):cookie生命等于0是一个特殊的值,它表示cookie被作废!也就是说,如果原来浏览器已经保存了这个Cookie,那么可以通过Cookie的setMaxAge(0)来删除这个Cookie。无论是在浏览器内存中,还是在客户端硬盘上都会删除这个Cookie。
2.5cookie的路径
(1)什么是Cookie的路径
WEB应用A,向客户端发送了10个Cookie,这就说明客户端无论访问应用A的哪个Servlet都会把这10个Cookie包含在请求中!但是也许只有AServlet需要读取请求中的Cookie,而其他Servlet根本就不会获取请求中的Cookie。这说明客户端浏览器有时发送这些Cookie是多余的!可以通过设置Cookie的path来指定浏览器,在访问什么样的路径时,包含什么样的Cookie。
(2)Cookie路径与请求路径的关系
Cookie路径的作用:
下面是客户端浏览器保存的3个Cookie的路径:
a:/cookietest;
b:/cookietest/servlet;
c:/cookietest/jsp;
下面是浏览器请求的URL:
A:http://localhost:8080/cookietest/AServlet;
B:http://localhost:8080/cookietest/servlet/BServlet;
C:http://localhost:8080/cookietest/jsp/CServlet;
请求A时,会在请求中包含a;
请求B时,会在请求中包含a、b;
请求C时,会在请求中包含a、c;
也就是说,请求路径如果包含了Cookie路径,那么会在请求中包含这个Cookie,否则不会请求中不会包含这个Cookie。
A请求的URL包含了“/cookietest”,所以会在请求中包含路径为“/cookietest”的Cookie;
B请求的URL包含了“/cookietest”,以及“/cookietest/servlet”,所以请求中包含路径为“/cookietest”和“/cookietest/servlet”两个Cookie;
B请求的URL包含了“/cookietest”,以及“/cookietest/jsp”,所以请求中包含路径为“/cookietest”和“/cookietest/jsp”两个Cookie;
(3)设置Cookie的路径
设置Cookie的路径需要使用setPath()方法,例如:
cookie.setPath(“/cookietest/servlet”);
如果没有设置Cookie的路径,那么Cookie路径的默认值当前访问资源所在路径,例如:
访问http://localhost:8080/cookietest/AServlet时添加的Cookie默认路径为/cookietest;
访问http://localhost:8080/cookietest/servlet/BServlet时添加的Cookie默认路径为/cookietest/servlet;
访问http://localhost:8080/cookietest/jsp/BServlet时添加的Cookie默认路径为/cookietest/jsp;
2.6 Cookie中保存中文
Cookie的name和value都不能使用中文,如果希望在Cookie中使用中文,那么需要先对中文进行URL编码,然后把编码后的字符串放到Cookie中。
(1)向客户端响应中添加Cookie
String name = URLEncoder.encode("姓名", "UTF-8");
String value = URLEncoder.encode("张三", "UTF-8");
Cookie c = new Cookie(name, value);
c.setMaxAge(3600);
response.addCookie(c);
(2)从客户端请求中获取Cookie
response.setContentType("text/html;charset=utf-8");
Cookie[] cs = request.getCookies();
if(cs != null) {
for(Cookie c : cs) {
String name = URLDecoder.decode(c.getName(), "UTF-8");
String value = URLDecoder.decode(c.getValue(), "UTF-8");
String s = name + ": " + value + "<br/>";
response.getWriter().print(s);
}
}
3. session
3.1 session概述
HttpSession是javax.servlet.http包下的一个接口,用来进行会话跟踪。HttpSession对象是Servlet的三大域对象之一,其他两个域对象是HttpServletRequest和ServletContext。这三个域中,request的域范围最小,它的域范围是整个请求链,并且只在请求转发和包含时存在;session域对象的域范围是一次会话,而在一次会话中会产生多次请求,因此session的域范围要比request大;application的域范围是最大的,因为一个web应用只有唯一的一个application对象,只有当web应用被移出服务器或服务器关闭它才死亡,它的域范围是整个应用。
3.2 session常用方法
(1)voidsetAttribute(String name,Object value):向域中添加域属性;
(2)ObjectgetAttribute(String name):从域中获取指定名称的属性值;
(3)VoidremoveAttribute(String name):移出域中指定名称的域属性
Session相关方法:
(a)String getId():获取sessionId;
(b)intgetMaxInactiveInterval():获取session可以的最大不活动时间(秒),默认为30分钟。当session在30分钟内没有使用,那么Tomcat会在session池中移除这个session;
(c)voidsetMaxInactiveInterval(int interval):设置session允许的最大不活动时间(秒),如果设置为1秒,那么只要session在1秒内不被使用,那么session就会被移除;
(d)long getCreationTime():返回session的创建时间,返回值为当前时间的毫秒值;
(e)longgetLastAccessedTime():返回session的最后活动时间,返回值为当前时间的毫秒值;
(f)voidinvalidate():让session失效!调用这个方法会被session失效,当session失效后,客户端再次请求,服务器会给客户端创建一个新的session,并在响应中给客户端新session的sessionId;
(g)booleanisNew():查看session是否为新。当客户端第一次请求时,服务器为客户端创建session,但这时服务器还没有响应客户端,也就是还没有把sessionId响应给客户端时,这时session的状态为新。
3.3 session对象的获取
如果请求时,cookie中有jsessionid这个cookie,那么request.getSession()就会根据jsessionid值查找session的id,如果查找到,会使用已有的,如果没有查找到,会创建。
如果请求时,cookie中没有jsessionid这个cookie,那么request.getSession()就会创建一个新的session对象.
3.4 session实现原理
session底层是依赖Cookie,当首次使用session时,服务器端要创建session,session是保存在服务器端,而给客户端的session的id(一个cookie中保存了sessionId)。客户端带走的是sessionId,而数据是保存在session中。
当客户端再次访问服务器时,在请求中会带上sessionId,而服务器会通过sessionId找到对应的session,而无需再创建新的session。
3.5 session对象的销毁分析
浏览器关闭了,session对象不会销毁的,session的销毁与关闭浏览器无关.
session对象销毁方式:
(1)关闭服务器
(2)默认超时
在tomcat/conf/web.xml文件中设置了session默认超时时间
<session-config>
<session-timeout>30</session-timeout>
</session-config>
默认30分钟超时
(3)可以设置session超时时间(以秒为单位)
void setMaxInactiveInterval(int interval)
(4)销毁session
invalidate();
3.6 session失效
session失效有如下几个原因:
(1)客户端的请求中没有sessionId。可能是因为这是第一次请求(开始一个新的会话),也可能是服务器设置Cookie的maxAge为0导致的;
(2)客户端请求中存在sessionId,但这个sessionId在session池中没有匹配的session对象。这可能是因为session太久没有使用,服务器把session从池中移除的原因;
(3)客户端请求中存在sessionId,但匹配的session对象被标记为失效!这可能是因为服务器调用了session.invalidate()方法导致的。
4. URL重写
4.1 URL重写概述
如果浏览器不支持Cookie或用户阻止了所有Cookie,可以把会话ID附加在HTML页面中所有的URL上,这些页面作为响应发送给客户。这样,当用户单击URL时,会话ID被自动作为请求头的一部分而不是作为头行发送回服务器。这种方法称为URL重写(URL rewriting)。
4.2 URL重写的作用
当客户机不接受cookie时,server就使用URL重写作为会话跟踪的基本方式,URL重写,添加了附加数据(会话ID)到请求的URL路径上。 会话ID必须被编码作为该URL字符串中的路径参数。该参数的名称为jsessionid,简单说就是cookie禁用了jsessionid就不能携带,那么每次请求,都是一个新的session对象。如果想要使用同一个session对象,可以使用url重写.
response.encodeRedirectURL(java.lang.String url)
用于对sendRedirect方法后的url地址进行重写。
response.encodeURL(java.lang.String url)
用于对表单action和超链接的url地址进行重写