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地址進行重寫