中文字幕日韩一区二区_国产一区二区av_国产毛片av_久久久久国产一区_色婷婷电影_国产一区二区精品

大話Session

引言

    在web開發(fā)中,session是個非常重要的概念。在許多動態(tài)網(wǎng)站的開發(fā)者看來,session就是一個變量,而且其表現(xiàn)像個黑洞,他只需要將東西在合適的時機放進這個洞里,等需要的時候再把東西取出來。這是開發(fā)者對session最直觀的感受,但是黑洞里的景象或者說session內(nèi)部到底是怎么工作的呢?當筆者向身邊的一些同事或朋友問及相關(guān)的更進一步的細節(jié)時,很多人往往要么含糊其辭要么主觀臆斷,所謂知其然而不知其所以然。

筆者由此想到很多開發(fā)者,包括我自己,每每都是糾纏于框架甚至二次開發(fā)平臺之上,而對于其下的核心和基礎(chǔ)知之甚少,或者有心無力甚至毫不關(guān)心,少了逐本溯源的精神,每憶及此,無不慚愧。曾經(jīng)實現(xiàn)過一個簡單的HttpServer,但當時由于知識儲備和時間的問題,沒有考慮到session這塊,不過近期在工作之余翻看了一些資料,并進行了相關(guān)實踐,小有所得,本著分享的精神,我將在本文中盡可能全面地將個人對于session的理解展現(xiàn)給讀者,同時盡我所能地論及一些相關(guān)的知識,以期讀者在對session有所了解的同時也能另有所悟,正所謂授人以漁。

Session是什么

    Session一般譯作會話,牛津詞典對其的解釋是進行某活動連續(xù)的一段時間。從不同的層面看待session,它有著類似但不全然相同的含義。比如,在web應(yīng)用的用戶看來,他打開瀏覽器訪問一個電子商務(wù)網(wǎng)站,登錄、并完成購物直到關(guān)閉瀏覽器,這是一個會話。而在web應(yīng)用的開發(fā)者開來,用戶登錄時我需要創(chuàng)建一個數(shù)據(jù)結(jié)構(gòu)以存儲用戶的登錄信息,這個結(jié)構(gòu)也叫做session。因此在談?wù)搒ession的時候要注意上下文環(huán)境。而本文談?wù)摰氖且环N基于HTTP協(xié)議的用以增強web應(yīng)用能力的機制或者說一種方案,它不是單指某種特定的動態(tài)頁面技術(shù),而這種能力就是保持狀態(tài),也可以稱作保持會話。

為什么需要session

    談及session一般是在web應(yīng)用的背景之下,我們知道web應(yīng)用是基于HTTP協(xié)議的,而HTTP協(xié)議恰恰是一種無狀態(tài)協(xié)議。也就是說,用戶從A頁面跳轉(zhuǎn)到B頁面會重新發(fā)送一次HTTP請求,而服務(wù)端在返回響應(yīng)的時候是無法獲知該用戶在請求B頁面之前做了什么的。

    對于HTTP的無狀態(tài)性的原因,相關(guān)RFC里并沒有解釋,但聯(lián)系到HTTP的歷史以及應(yīng)用場景,我們可以推測出一些理由:

1.   設(shè)計HTTP最初的目的是為了提供一種發(fā)布和接收HTML頁面的方法。那個時候沒有動態(tài)頁面技術(shù),只有純粹的靜態(tài)HTML頁面,因此根本不需要協(xié)議能保持狀態(tài);

2.   用戶在收到響應(yīng)時,往往要花一些時間來閱讀頁面,因此如果保持客戶端和服務(wù)端之間的連接,那么這個連接在大多數(shù)的時間里都將是空閑的,這是一種資源的無端浪費。所以HTTP原始的設(shè)計是默認短連接,即客戶端和服務(wù)端完成一次請求和響應(yīng)之后就斷開TCP連接,服務(wù)器因此無法預(yù)知客戶端的下一個動作,它甚至都不知道這個用戶會不會再次訪問,因此讓HTTP協(xié)議來維護用戶的訪問狀態(tài)也全然沒有必要;

3.   將一部分復(fù)雜性轉(zhuǎn)嫁到以HTTP協(xié)議為基礎(chǔ)的技術(shù)之上可以使得HTTP在協(xié)議這個層面上顯得相對簡單,而這種簡單也賦予了HTTP更強的擴展能力。事實上,session技術(shù)從本質(zhì)上來講也是對HTTP協(xié)議的一種擴展。

總而言之,HTTP的無狀態(tài)是由其歷史使命而決定的。但隨著網(wǎng)絡(luò)技術(shù)的蓬勃發(fā)展,人們再也不滿足于死板乏味的靜態(tài)HTML,他們希望web應(yīng)用能動起來,于是客戶端出現(xiàn)了腳本和DOM技術(shù),HTML里增加了表單,而服務(wù)端出現(xiàn)了CGI等等動態(tài)技術(shù)。

而正是這種web動態(tài)化的需求,給HTTP協(xié)議提出了一個難題:一個無狀態(tài)的協(xié)議怎樣才能關(guān)聯(lián)兩次連續(xù)的請求呢?也就是說無狀態(tài)的協(xié)議怎樣才能滿足有狀態(tài)的需求呢?

此時有狀態(tài)是必然趨勢而協(xié)議的無狀態(tài)性也是木已成舟,因此我們需要一些方案來解決這個矛盾,來保持HTTP連接狀態(tài),于是出現(xiàn)了cookie和session。

對于此部分內(nèi)容,讀者或許會有一些疑問,筆者在此先談兩點:

1.   無狀態(tài)性和長連接

可能有人會問,現(xiàn)在被廣泛使用的HTTP1.1默認使用長連接,它還是無狀態(tài)的嗎?

連接方式和有無狀態(tài)是完全沒有關(guān)系的兩回事。因為狀態(tài)從某種意義上來講就是數(shù)據(jù),而連接方式只是決定了數(shù)據(jù)的傳輸方式,而不能決定數(shù)據(jù)。長連接是隨著計算機性能的提高和網(wǎng)絡(luò)環(huán)境的改善所采取的一種合理的性能上的優(yōu)化,一般情況下,web服務(wù)器會對長連接的數(shù)量進行限制,以免資源的過度消耗。

2.   無狀態(tài)性和session

        Session是有狀態(tài)的,而HTTP協(xié)議是無狀態(tài)的,二者是否矛盾呢?

    Session和HTTP協(xié)議屬于不同層面的事物,后者屬于ISO七層模型的最高層應(yīng)用層,前者不屬于后者,前者是具體的動態(tài)頁面技術(shù)來實現(xiàn)的,但同時它又是基于后者的。在下文中筆者會分析Servlet/Jsp技術(shù)中的session機制,這會使你對此有更深刻的理解。

Cookie和Session

    上面提到解決HTTP協(xié)議自身無狀態(tài)的方式有cookie和session。二者都能記錄狀態(tài),前者是將狀態(tài)數(shù)據(jù)保存在客戶端,后者則保存在服務(wù)端。

    首先看一下cookie的工作原理,這需要有基本的HTTP協(xié)議基礎(chǔ)。

cookie是在RFC2109(已廢棄,被RFC2965取代)里初次被描述的,每個客戶端最多保持三百個cookie,每個域名下最多20個Cookie(實際上一般瀏覽器現(xiàn)在都比這個多,如Firefox是50個),而每個cookie的大小為最多4K,不過不同的瀏覽器都有各自的實現(xiàn)。對于cookie的使用,最重要的就是要控制cookie的大小,不要放入無用的信息,也不要放入過多信息。

    無論使用何種服務(wù)端技術(shù),只要發(fā)送回的HTTP響應(yīng)中包含如下形式的頭,則視為服務(wù)器要求設(shè)置一個cookie:

Set-cookie:name=name;expires=date;path=path;domain=domain

    支持cookie的瀏覽器都會對此作出反應(yīng),即創(chuàng)建cookie文件并保存(也可能是內(nèi)存cookie),用戶以后在每次發(fā)出請求時,瀏覽器都要判斷當前所有的cookie中有沒有沒失效(根據(jù)expires屬性判斷)并且匹配了path屬性的cookie信息,如果有的話,會以下面的形式加入到請求頭中發(fā)回服務(wù)端:

    Cookie: name="zj"; Path="/linkage"

    服務(wù)端的動態(tài)腳本會對其進行分析,并做出相應(yīng)的處理,當然也可以選擇直接忽略。

    這里牽扯到一個規(guī)范(或協(xié)議)與實現(xiàn)的問題,簡單來講就是規(guī)范規(guī)定了做成什么樣子,那么實現(xiàn)就必須依據(jù)規(guī)范來做,這樣才能互相兼容,但是各個實現(xiàn)所使用的方式卻不受約束,也可以在實現(xiàn)了規(guī)范的基礎(chǔ)上超出規(guī)范,這就稱之為擴展了。無論哪種瀏覽器,只要想提供cookie的功能,那就必須依照相應(yīng)的RFC規(guī)范來實現(xiàn)。所以這里服務(wù)器只管發(fā)Set-cookie頭域,這也是HTTP協(xié)議無狀態(tài)性的一種體現(xiàn)。

需要注意的是,出于安全性的考慮,cookie可以被瀏覽器禁用。

    再看一下session的原理:

    筆者沒有找到相關(guān)的RFC,因為session本就不是協(xié)議層面的事物。它的基本原理是服務(wù)端為每一個session維護一份會話信息數(shù)據(jù),而客戶端和服務(wù)端依靠一個全局唯一的標識來訪問會話信息數(shù)據(jù)。用戶訪問web應(yīng)用時,服務(wù)端程序決定何時創(chuàng)建session,創(chuàng)建session可以概括為三個步驟:

1.   生成全局唯一標識符(sessionid);

2.   開辟數(shù)據(jù)存儲空間。一般會在內(nèi)存中創(chuàng)建相應(yīng)的數(shù)據(jù)結(jié)構(gòu),但這種情況下,系統(tǒng)一旦掉電,所有的會話數(shù)據(jù)就會丟失,如果是電子商務(wù)網(wǎng)站,這種事故會造成嚴重的后果。不過也可以寫到文件里甚至存儲在數(shù)據(jù)庫中,這樣雖然會增加I/O開銷,但session可以實現(xiàn)某種程度的持久化,而且更有利于session的共享;

3.   將session的全局唯一標示符發(fā)送給客戶端。

問題的關(guān)鍵就在服務(wù)端如何發(fā)送這個session的唯一標識上。聯(lián)系到HTTP協(xié)議,數(shù)據(jù)無非可以放到請求行、頭域或Body里,基于此,一般來說會有兩種常用的方式:cookie和URL重寫。

1.   Cookie

讀者應(yīng)該想到了,對,服務(wù)端只要設(shè)置Set-cookie頭就可以將session的標識符傳送到客戶端,而客戶端此后的每一次請求都會帶上這個標識符,由于cookie可以設(shè)置失效時間,所以一般包含session信息的cookie會設(shè)置失效時間為0,即瀏覽器進程有效時間。至于瀏覽器怎么處理這個0,每個瀏覽器都有自己的方案,但差別都不會太大(一般體現(xiàn)在新建瀏覽器窗口的時候);

2.   URL重寫

所謂URL重寫,顧名思義就是重寫URL。試想,在返回用戶請求的頁面之前,將頁面內(nèi)所有的URL后面全部以get參數(shù)的方式加上session標識符(或者加在path info部分等等),這樣用戶在收到響應(yīng)之后,無論點擊哪個鏈接或提交表單,都會在再帶上session的標識符,從而就實現(xiàn)了會話的保持。讀者可能會覺得這種做法比較麻煩,確實是這樣,但是,如果客戶端禁用了cookie的話,URL重寫將會是首選。

    到這里,讀者應(yīng)該明白我前面為什么說session也算作是對HTTP的一種擴展了吧。如下兩幅圖是筆者在Firefox的Firebug插件中的截圖,可以看到,當我第一次訪問index.jsp時,響應(yīng)頭里包含了Set-cookie頭,而請求頭中沒有。當我再次刷新頁面時,圖二顯示在響應(yīng)中不在有Set-cookie頭,而在請求頭中卻有了Cookie頭。注意一下Cookie的名字:jsessionid,顧名思義,就是session的標識符,另外可以看到兩幅圖中的jsessionid的值是相同的,原因筆者就不再多解釋了。另外讀者可能在一些網(wǎng)站上見過在最后附加了一段形如jsessionid=xxx的URL,這就是采用URL重寫來實現(xiàn)的session。

(圖一,首次請求index.jsp)

 

(圖二,再次請求index.jsp)

Cookie和session由于實現(xiàn)手段不同,因此也各有優(yōu)缺點和各自的應(yīng)用場景:

1.   應(yīng)用場景

Cookie的典型應(yīng)用場景是Remember Me服務(wù),即用戶的賬戶信息通過cookie的形式保存在客戶端,當用戶再次請求匹配的URL的時候,賬戶信息會被傳送到服務(wù)端,交由相應(yīng)的程序完成自動登錄等功能。當然也可以保存一些客戶端信息,比如頁面布局以及搜索歷史等等。

Session的典型應(yīng)用場景是用戶登錄某網(wǎng)站之后,將其登錄信息放入session,在以后的每次請求中查詢相應(yīng)的登錄信息以確保該用戶合法。當然還是有購物車等等經(jīng)典場景;

2.   安全性

cookie將信息保存在客戶端,如果不進行加密的話,無疑會暴露一些隱私信息,安全性很差,一般情況下敏感信息是經(jīng)過加密后存儲在cookie中,但很容易就會被竊取。而session只會將信息存儲在服務(wù)端,如果存儲在文件或數(shù)據(jù)庫中,也有被竊取的可能,只是可能性比cookie小了太多。

Session安全性方面比較突出的是存在會話劫持的問題,這是一種安全威脅,這在下文會進行更詳細的說明。總體來講,session的安全性要高于cookie;

3.   性能

Cookie存儲在客戶端,消耗的是客戶端的I/O和內(nèi)存,而session存儲在服務(wù)端,消耗的是服務(wù)端的資源。但是session對服務(wù)器造成的壓力比較集中,而cookie很好地分散了資源消耗,就這點來說,cookie是要優(yōu)于session的;

4.   時效性

Cookie可以通過設(shè)置有效期使其較長時間內(nèi)存在于客戶端,而session一般只有比較短的有效期(用戶主動銷毀session或關(guān)閉瀏覽器后引發(fā)超時);

5.   其他

Cookie的處理在開發(fā)中沒有session方便。而且cookie在客戶端是有數(shù)量和大小的限制的,而session的大小卻只以硬件為限制,能存儲的數(shù)據(jù)無疑大了太多。

Servlet/JSP中的Session

    通過上述的講解,讀者應(yīng)該對session有了一個大體的認識,但是具體到某種動態(tài)頁面技術(shù),又是怎么實現(xiàn)session的呢?下面筆者將結(jié)合session的生命周期(lifecycle),從源代碼的層次來具體分析一下在servlet/jsp技術(shù)中,session是怎么實現(xiàn)的。代碼部分以tomcat6.0.20作為參考。

創(chuàng)建

在我問過的一些從事Java web開發(fā)的人中,對于session的創(chuàng)建時機大都這么回答:當我請求某個頁面的時候,session就被創(chuàng)建了。這句話其實很含糊,因為要創(chuàng)建session請求的發(fā)送是必不可少的,但是無論何種請求都會創(chuàng)建session嗎?錯。我們來看一個例子。

眾所周知,jsp技術(shù)是servlet技術(shù)的反轉(zhuǎn),在開發(fā)階段,我們看到的是jsp頁面,但真正到運行時階段,jsp頁面是會被“翻譯”為servlet類來執(zhí)行的,例如我們有如下jsp頁面:

<%@ page language="Java" pageEncoding="ISO-8859-1" session="true"%>

DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

    <head>

        <title>index.jsptitle>

    head>

    <body>

        This is index.jsp page.

        <br>

    body>

html>

    在我們初次請求該頁面后,在對應(yīng)的work目錄可以找到該頁面對應(yīng)的Java類,考慮到篇幅的原因,在此只摘錄比較重要的一部分,有興趣的讀者可以親自試一下:

......

response.setContentType("text/html;charset=ISO-8859-1");

pageContext = _jspxFactory.getPageContext(this, request, response,

            null, true, 8192, true);

_jspx_page_context = pageContext;

application = pageContext.getServletContext();

config = pageContext.getServletConfig();

session = pageContext.getSession();

out = pageContext.getOut();

_jspx_out = out;

 

out.write("/r/n");

out.write("/r/n");

out.write("/r/n");

......

    可以看到有一句顯式創(chuàng)建session的語句,它是怎么來的呢?我們再看一下對應(yīng)的jsp頁面,在jsp的page指令中加入了session="true",意思是在該頁面啟用session,其實作為動態(tài)技術(shù),這個參數(shù)是默認為true的,這很合理,在此顯示寫出來只是做一下強調(diào)。很顯然二者有著必然的聯(lián)系。筆者在jsp/servlet的翻譯器(org.apache.jASPer.compiler)的源碼中找到了相關(guān)證據(jù):

......

if (pageInfo.isSession())

    out.printil("session = pageContext.getSession();");

out.printil("out = pageContext.getOut();");

out.printil("_jspx_out = out;");

......

    上面的代碼片段的意思是如果頁面中定義了session="true",就在生成的servlet源碼中加入session的獲取語句。這只能夠說明session創(chuàng)建的條件,顯然還不能說明session是如何創(chuàng)建的,本著逐本溯源的精神,我們繼續(xù)往下探索。

    有過servlet開發(fā)經(jīng)驗的應(yīng)該記得我們是通過HttpServletRequest的getSession方法來獲取當前的session對象的:

public HttpSession getSession(boolean create);

public HttpSession getSession();

    二者的區(qū)別只是無參的getSession將create默認設(shè)置為true而已。即:

public HttpSession getSession() {

    return (getSession(true));

}

    那么這個參數(shù)到底意味著什么呢?通過層層跟蹤,筆者終于理清了其中的脈絡(luò),由于函數(shù)之間的關(guān)系比較復(fù)雜,如果想更詳細地了解內(nèi)部機制,建議去獨立閱讀tomcat相關(guān)部分的源代碼。這里我將其中的大致流程敘述一下:

1.   用戶請求某jsp頁面,該頁面設(shè)置了session="true";

2.   Servlet/jsp容器將其翻譯為servlet,并加載、執(zhí)行該servlet;

3.   Servlet/jsp容器在封裝HttpServletRequest對象時根據(jù)cookie或者url中是否存在jsessionid來決定是綁定當前的session到HttpRequest還是創(chuàng)建新的session對象(在請求解析階段發(fā)現(xiàn)并記錄jsessionid,在Request對象創(chuàng)建階段將session綁定);

4.   程序按需操作session,存取數(shù)據(jù);

5.   如果是新創(chuàng)建的session,在結(jié)果響應(yīng)時,容器會加入Set-cookie頭,以提醒瀏覽器要保持該會話(或者采用URL重寫方式將新的鏈接呈現(xiàn)給用戶)。

通過上面的敘述讀者應(yīng)該了解了session是何時創(chuàng)建的,這里再從servlet這個層面總結(jié)一下:當用戶請求的servlet調(diào)用了getSession方法時,都會獲取session,至于是否創(chuàng)建新的session取決于當前request是否已綁定session。當客戶端在請求中加入了jsessionid標識而servlet容器根據(jù)此標識查找到了對應(yīng)的session對象時,會將此session綁定到此次請求的request對象,客戶端請求中不帶jsessionid或者此jsessionid對應(yīng)的session已過期失效時,session的綁定無法完成,此時必須創(chuàng)建新的session。同時發(fā)送Set-cookie頭通知客戶端開始保持新的會話。

保持

    理解了session的創(chuàng)建,就很好理解會話是如何在客戶端和服務(wù)端之間保持的了。當首次創(chuàng)建了session后,客戶端會在后續(xù)的請求中將session的標識符帶到服務(wù)端,服務(wù)端程序只要在需要session的時候調(diào)用getSession,服務(wù)端就可以將對應(yīng)的session綁定到當前請求,從而實現(xiàn)狀態(tài)的保持。當然這需要客戶端的支持,如果禁用了cookie而又不采用url重寫的話,session是無法保持的。

    如果幾次請求之間有一個servlet未調(diào)用getSession(或者干脆請求一個靜態(tài)頁面)會不會使得會話中斷呢?這個不會發(fā)生的,因為客戶端只會將合法的cookie值傳送給服務(wù)端,至于服務(wù)端拿cookie做什么事它是不會關(guān)心的,當然也無法關(guān)心。Session建立之后,客戶端會一直將session的標識符傳送到服務(wù)器,無論請求的頁面是動態(tài)的、靜態(tài)的,甚至是一副圖片。

銷毀

    此處談到的銷毀是指會話的廢棄,至于存儲會話信息的數(shù)據(jù)結(jié)構(gòu)是回收被重用還是直接釋放內(nèi)存我們并不關(guān)心。Session的銷毀有兩種情況:超時和手動銷毀。

    由于HTTP協(xié)議的無狀態(tài)性,服務(wù)端無法得知一個session對象何時將再次被使用,可能用戶開啟了一個session之后再也沒有后續(xù)的訪問,而且session的保持是需要消耗一定的服務(wù)端開銷的,因此不可能一味地創(chuàng)建session而不去回收無用的session。這里就引入了一個超時機制。Tomcat中的超時在web.xml里做如下配置:

 

30

 

    上述配置是指session在30分鐘沒有被再次使用就將其銷毀。Tomcat是怎么計算這個30分鐘的呢?原來在getSession之后,都要調(diào)用它的access方法,修改lastAccessedTime,在銷毀session的時候就是判斷當前時間和這個lastAccessedTime的差值。

    手動銷毀是指直接調(diào)用其invalidate方法,此方法實際上是調(diào)用expire方法來手動將其設(shè)置為超時。

    當用戶手動請求了session的銷毀時,客戶端是無法知道服務(wù)端的session已經(jīng)被銷毀的,它依然會發(fā)送先前的session標識符到服務(wù)端。而此時如果再次請求了某個調(diào)用了getSession的servlet,服務(wù)端是無法根據(jù)先前的session標識符找到相應(yīng)的session對象的,這是又要重新創(chuàng)建新的session,分配新的標識符,并告知服務(wù)端更新session標識符開始保持新的會話。

Session的數(shù)據(jù)結(jié)構(gòu)

    在servlet/jsp中,容器是用何種數(shù)據(jù)結(jié)構(gòu)來存儲session相關(guān)的變量的呢?我們猜測一下,首先它必須被同步操作,因為在多線程環(huán)境下session是線程間共享的,而web服務(wù)器一般情況下都是多線程的(為了提高性能還會用到池技術(shù));其次,這個數(shù)據(jù)結(jié)構(gòu)必須容易操作,最好是傳統(tǒng)的鍵值對的存取方式。

    那么我們先具體到單個session對象,它除了存儲自身的相關(guān)信息,比如id之外,tomcat的session還提供給程序員一個用以存儲其他信息的接口(在類org.apache.catalina.session. StandardSession里):

public void setAttribute(String name, Object value, boolean notify)

    在這里可以追蹤到它到底使用了何種數(shù)據(jù):

protected Map attributes = new ConcurrentHashMap();

    這就很明確了,原來tomcat使用了一個ConcurrentHashMap對象存儲數(shù)據(jù),這是Java的concurrent包里的一個類。它剛好滿足了我們所猜測的兩點需求:同步與易操作性。

    那么tomcat又是用什么數(shù)據(jù)結(jié)構(gòu)來存儲所有的session對象呢?果然還是ConcurrentHashMap(在管理session的org.apache.catalina.session. ManagerBase類里):

protected Map sessions = new ConcurrentHashMap();

    具體原因就不必多說了。至于其他web服務(wù)器的具體實現(xiàn)也應(yīng)該考慮到這兩點。

Session Hijack

    Session hijack即會話劫持是一種比較嚴重的安全威脅,也是一種廣泛存在的威脅,在session技術(shù)中,客戶端和服務(wù)端通過傳送session的標識符來維護會話,但這個標識符很容易就能被嗅探到,從而被其他人利用,這屬于一種中間人攻擊。

本部分通過一個實例來說明何為會話劫持,通過這個實例,讀者其實更能理解session的本質(zhì)。

首先,我編寫了如下頁面:

<%@ page language="Java" pageEncoding="ISO-8859-1" session="true"%>

DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

    <head>

       <title>index.jsptitle>

    head>

    <body>

       This is index.jsp page.

       <br>

       <%

           Object o = session.getAttribute("counter");

           if (o == null) {

              session.setAttribute("counter", 1);

           } else {

              Integer i = Integer.parseInt(o.toString());

              session.setAttribute("counter", i + 1);

           }

           out.println(session.getAttribute("counter"));

       %>

       <a href="<%=response.encodeRedirectURL("index.jsp")%>">indexa>

    body>

html>

    頁面的功能是在session中放置一個計數(shù)器,第一次訪問該頁面,這個計數(shù)器的值初始化為1,以后每一次訪問這個頁面計數(shù)器都加1。計數(shù)器的值會被打印到頁面。另外,為了比較簡單地模擬,筆者禁用了客戶端(采用firefox3.0)的cookie,轉(zhuǎn)而改用URL重寫方式,因為直接復(fù)制鏈接要比偽造cookie方便多了。

    下面,打開firefox訪問該頁面,我們看到了計數(shù)器的值為1:

 

(圖三)

    然后點擊index鏈接來刷新計數(shù)器,注意不要刷新當前頁,因為我們沒用采用cookie的方式,只能在url后面帶上jsessionid,而此時地址欄里的url是無法帶上jsessionid的。如圖四,我把計數(shù)器刷新到了20。

 

(圖四)

    下面是最關(guān)鍵的,復(fù)制firefox地址欄里的地址(筆者看到的是http://localhost:8080/sessio

n/index.jsp;jsessionid=1380D9F60BCE9C30C3A7CBF59454D0A5),然后打開另一個瀏覽器,此處不必將其cookie禁用。這里我打開了蘋果的safari3瀏覽器,然后將地址粘貼到其地址欄里,回車后如下圖:

 

(圖五)

    很奇怪吧,計數(shù)器直接到了21。這個例子筆者是在同一臺計算機上做的,不過即使換用兩臺來做,其結(jié)果也是一樣的。此時如果交替點擊兩個瀏覽器里的index鏈接你會發(fā)現(xiàn)他們其實操縱的是同一個計數(shù)器。其實不必驚訝,此處safari盜用了firefox和tomcat之間的維持會話的鑰匙,即jsessionid,這屬于session hijack的一種。在tomcat看來,safari交給了它一個jsessionid,由于HTTP協(xié)議的無狀態(tài)性,它無法得知這個jsessionid是從firefox那里“劫持”來的,它依然會去查找對應(yīng)的session,并執(zhí)行相關(guān)計算。而此時firefox也無法得知自己的保持會話已經(jīng)被“劫持”。

結(jié)語

    到這里,讀者應(yīng)該對session有了更多的更深層次的了解,不過由于筆者的水平以及視野有限,文中也不乏表述欠妥之處,通篇更多地描述了在servlet/jsp中的session機制,但其他開發(fā)平臺的機制也都萬變不離其宗。只要認真思考,你會發(fā)現(xiàn)其實這里林林總總之間,總有一些因果關(guān)系存在。在軟件規(guī)模日益增大的背景下,我們更多的時候接觸到的是框架、組件,程序員的雙眼被蒙蔽了,在這些框架、組件不斷產(chǎn)生以及版本的不斷更新中,其實有很多相對不變的東西,那就是規(guī)范、協(xié)議、模式、算法等等,真正令一個人得到提高的還是那些底層的支撐技術(shù)。平時多多思考的話,你就能把類似的探索轉(zhuǎn)化為印證。做技術(shù)猶如解牛,知筋知骨方能游刃有余。

轉(zhuǎn)載請保留出處:shoru.cnblogs.com 晉哥哥的私房錢

NET技術(shù)大話Session,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 中文字幕一区二区三区精彩视频 | 久久久久1 | 午夜精品一区二区三区在线观看 | 人干人人| 午夜视频在线播放 | 一区二区三区在线看 | 91av在线不卡 | 91国产精品在线 | 美女在线观看国产 | 日韩av黄色 | 精品成人av| 日本三级电影免费观看 | 国产欧美视频一区二区 | 久久久久久国产精品三区 | 精品免费看| 成人免费一区二区三区牛牛 | 久久999| av日韩精品 | 91在线| 色视频在线观看 | 国产高清视频一区二区 | 成人在线视频免费看 | 久久久久久亚洲精品 | 天天看天天操 | 男女视频在线观看免费 | 中文字幕在线视频免费视频 | 欧美综合久久久 | 日本午夜免费福利视频 | 国产成人福利 | 黄色一级大片在线免费看产 | 国产一级网站 | 国产区在线 | 91久久久久久久久久久久久 | 亚州成人| 在线视频91 | 91久久精品国产91久久 | 老司机67194精品线观看 | 国产日韩欧美在线播放 | 成年男女免费视频网站 | 久久黄色| 成人欧美一区二区三区白人 |