http的無狀态,也就是說,每次請求都是獨立的線程。舉個例子吧:購物中,你選擇了a商品,加入購物車,這就是a線程。然後在選擇b商品就是b線程。可是每次線程獨立(對容器而言,a、b成了不同的使用者),線程a不知道有b,b也不知道a。如何一起付款呢?
簡答來說:怎麼儲存同個使用者多個請求會話狀态呢?自然https保證連接配接是安全的,可以使它與一個會話關聯。
問題就在于如何跟蹤同一個使用者,選擇自然很多:
1、ejb(有狀态會話bean儲存會話狀态) 環境苛刻需要帶ejb的j2ee伺服器,而不是tomcat這種web容器。 2、資料庫(這貌似萬能的。針對資料) 3、就是我們要講的httpseesion,儲存跨一個特定使用者多個請求的會話狀态。 4、上面說的https,條件太苛刻了。

機制,什麼用詞有點高大上。其實就是把它内在的一點東西說出來。主要兩個w:what?how?
what is session?
session代表着伺服器和用戶端一次會話的過程。直到session失效(服務端關閉),或者用戶端關閉時結束。
how does session works?
session 是存儲在服務端的,并針對每個用戶端(客戶),通過sessionid來差別不同使用者的。session是以cookie技術或url重寫實作。預設以cookie技術實作,服務端會給這次會話創造一個jsessionid的cookie值。
補充:
其實還有一種技術:表單隐藏字段。它也可以實作session機制。這裡隻是作為補充,伺服器響應前,會修改form表單,添加一個sessionid類似的隐藏域,以便傳回服務端的時候可以标示出此會話。 這技術,也可以使用在web安全上,可以有效地控制crsf跨站請求僞造。
圖中這是session第一次請求的詳細圖。以cookie技術實作,我也寫了個httpsessionbycookieservlett.java 的servlet小demo,模拟下seesion的一生。代碼如下:
<a href="http://www.bysocket.com/?p=384#">?</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<code>package</code> <code>org.servlet.sessionmngmt;</code>
<code>import</code> <code>java.io.ioexception;</code>
<code>import</code> <code>java.io.printwriter;</code>
<code>import</code> <code>javax.servlet.servletexception;</code>
<code>import</code> <code>javax.servlet.annotation.webservlet;</code>
<code>import</code> <code>javax.servlet.http.httpservlet;</code>
<code>import</code> <code>javax.servlet.http.httpservletrequest;</code>
<code>import</code> <code>javax.servlet.http.httpservletresponse;</code>
<code>import</code> <code>javax.servlet.http.httpsession;</code>
<code>/*</code>
<code> </code><code>* copyright [2015] [jeff lee]</code>
<code> </code><code>*</code>
<code> </code><code>* licensed under the apache license, version 2.0 (the "license");</code>
<code> </code><code>* you may not use this file except in compliance with the license.</code>
<code> </code><code>* you may obtain a copy of the license at</code>
<code> </code><code>* unless required by applicable law or agreed to in writing, software</code>
<code> </code><code>* distributed under the license is distributed on an "as is" basis,</code>
<code> </code><code>* without warranties or conditions of any kind, either express or implied.</code>
<code> </code><code>* see the license for the specific language governing permissions and</code>
<code> </code><code>* limitations under the license.</code>
<code> </code><code>*/</code>
<code>/**</code>
<code> </code><code>* @author jeff lee</code>
<code> </code><code>* @since 2015-7-12 10:58:28</code>
<code> </code><code>* httpsession的預設cookie實作案例</code>
<code>@webservlet</code><code>(urlpatterns =</code><code>"/sessionbycookie"</code><code>)</code>
<code>public</code> <code>class</code> <code>httpsessionbycookieservlett</code><code>extends</code> <code>httpservlet {</code>
<code> </code><code>private</code> <code>static</code> <code>final</code> <code>long</code> <code>serialversionuid = 1l;</code>
<code> </code><code>@override</code>
<code> </code><code>protected</code> <code>void</code> <code>doget(httpservletrequest req, httpservletresponse resp)</code>
<code> </code><code>throws</code> <code>servletexception, ioexception {</code>
<code> </code>
<code> </code><code>// 擷取session</code>
<code> </code><code>// 如果是第一次請求的話,會建立一個httpseesion,等同于 req.getsession(true);</code>
<code> </code><code>// 如果已存在session,則會擷取session。</code>
<code> </code><code>httpsession session = req.getsession();</code>
<code> </code><code>if</code> <code>(session.isnew()) {</code>
<code> </code><code>// 設定session屬性值</code>
<code> </code><code>session.setattribute(</code><code>"name"</code><code>,</code><code>"jeff"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>// 擷取sessionid</code>
<code> </code><code>string sessionid = session.getid();</code>
<code> </code><code>printwriter out = resp.getwriter();</code>
<code> </code><code>// 如果httpseesion是建立的話</code>
<code> </code><code>out.println(</code><code>"hello,httpsession! <br>the first response - seesionid="</code>
<code> </code><code>+ sessionid +</code><code>" <br>"</code><code>);</code>
<code> </code><code>}</code><code>else</code> <code>{</code>
<code> </code><code>out.println(</code><code>"hello,httpsession! <br>the second response - seesionid="</code>
<code> </code><code>// 從session擷取屬性值</code>
<code> </code><code>out.println(</code><code>"the second-response - name: "</code>
<code> </code><code>+ session.getattribute(</code><code>"name"</code><code>));</code>
<code> </code><code>}</code>
<code> </code>
<code>}</code>
隆重打個小廣告:
① 用戶端向服務端發送第一次請求
此時,用戶端想讓服務端把自己的名字設定到會話中。
② 服務端的容器産生該使用者唯一sessionid的session對象,并設定值
可以從代碼中看出通過從請求中req.getsession(),新生成了一個session對象。并設定了setattribute(“name”, “jeff”),key為string,value是對象皆可。
這時候,我們不用再把session通過cookie技術處理,容器幫我們處理了。
③ 容器響應 set-cookie:jsessionid= …
我們可以f12,檢視此次響應。
從圖中可得到,每個cookie的set,都有一個對應set-cookie的頭。httponly可是此cookie隻讀模式。隻不過session唯一辨別是:jsessionid
④ 浏覽器解析cookie,儲存至浏覽器檔案。
第二次請求會發什麼變化呢?
下面,泥瓦匠重新通路了這個位址:
① 再次請求
此時,請求會有cookie值:jsessionid=… 該值傳給服務端
② 容器擷取sessionid
,關聯httpsession
③ 此時響應無setcookie
如圖:
但是這次請求,我們響應出上一次請求set的值。jeff 就列印出來了!
關于服務端擷取session,也就是從請求中擷取session對象,容器會幫你根據cookie找到唯一的session對象。
泥瓦匠記憶小抄:seesion機制,記住兩次請求圖即可。
點到為止哈~ 以後詳細寫。此圖來自網絡
上圖bad guy,就是攻擊者。跨站請求僞造,僞造使用者請求來對伺服器資料或者是使用者等造成威脅。web安全也就是從這些基礎中慢慢提升。
1、大概地描述了session的工作機制,和一些安全相關。記住seesion是什麼,怎麼用,在服務端用戶端之間怎麼傳輸即可。