java_web学习(8)会话与状态管
HTTP簡介
WEB瀏覽器與WEB服務器之間的一問一答的交互過程必須遵循一定的規則,這個規則就是HTTP協議。HTTP是hypertext transfer protocol(超文本傳輸協議)的簡寫,它是TCP/IP協議集中的一個應用層協議,用于定義WEB瀏覽器與WEB服務器之間交換數據的過程以及數據本身的格式。 HTTP協議的版本:? HTTP/1.0、HTTP/1.1、HTTP-NG HTTP 的會話方式 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?瀏覽器訪問多圖網頁的過程 ? ?? 瀏覽器與WEB服務器的連接過程是短暫的,每次連接只處理一個請求和響應。對每一個頁面的訪問,瀏覽器與WEB服務器都要建立一次單獨的連接。瀏覽器到WEB服務器之間的所有通訊都是完全獨立分開的請求和響應對。 HTTP請求消息與響應消息 請求消息的結構:一個請求行、若干消息頭、以及實體內容,其中的一些消息頭和實體內容都是可選的,消息頭和實體內容之間要用空行隔開。 一個使用GET方式的請求消息中不能包含實體內容,只有使用POST、PUT和DELETE方式的請求消息中才可以包含實體內容。? 響應消息的結構:一個狀態行、若干消息頭、以及實體內容 ,其中的一些消息頭和實體內容都是可選的,消息頭和實體內容之間要用空行隔開。 響應消息的實體內容就是網頁文件的內容,也就是在瀏覽器中使用查看源文件的方式所看到的內容。? ? ? ? ? ? ? ? ? ? ?? HTTP消息頭 1>使用消息頭,可以實現HTTP客戶機與服務器之間的條件請求和應答,消息頭相當于服務器和瀏覽器之間的一些暗號指令。 2>每個消息頭包含一個頭字段名稱,然后依次是冒號、空格、值、回車和換行符。 3>消息頭字段名是不區分大小寫的,但習慣上將每個單詞的第一個字母大寫。 4>整個消息頭部分中的各行消息頭可按任何順序排列。? 5>消息頭又可以分為通用信息頭、請求頭、響應頭、實體頭等四類。 6>許多請求頭字段都允許客戶端在值部分指定多個可接受的選項,多個項之間以逗號分隔。 7>有些頭字段可以出現多次。 請求行與狀態行 請求行? ? ? ? ? ?格式:請求方式 資源路徑 HTTP版本號<CRLF> ? ??舉例:GET /test.html HTTP/1.1
? ? ? ? ? ?請求方式:POST、HEAD、OPTIONS、DELETE、TRACE、PUT
狀態行? ? ? ? ? ?格式: HTTP版本號 狀態碼 原因敘述<CRLF> ? ? ??舉例:HTTP/1.1 200 OK
使用GET和POST方式傳遞參數 在URL地址后面可以附加一些參數 ??舉例:http://www.it315.org/servlet/ParamsServlet?param1=abc¶m2=xyz GET方式: 1)當用戶在瀏覽器地址欄中直接輸入某個url地址或者單擊網頁上一個超鏈接時,瀏覽器使用get方式發送請求。? ? ? ? ? ? ? ? ?2)當網頁行的form標單的method屬性設定為"GET",或者沒有設置method屬性(默認為GET),提交表單時,瀏覽器也用get方式發送請求。
? ? ? ? ? ? ? ? ?使用GET請求方式給WEB服務器傳遞參數的格式:http://www.it315.org/counter.jsp?name=zhangsan&password=123
? ? ? ? ? ? ? ? ?使用GET方式傳送的數據量一般限制在1KB以下。
GET /servlet/ParamsServlet?param1=abc¶m2=xyz HTTP/1.1 POST方式: 1)POST請求方式主要用于向WEB服務器端程序提交FORM表單中的數據,當網頁行的form標單的method屬性設定為"POST"時,提交表單時,瀏覽器使用post方式發送請求。? ? ? ? ? ? ? ? 2)POST方式將各個表單字段元素及其數據作為HTTP消息的實體內容發送給WEB服務器,傳送的數據量要比使用GET方式傳送的數據量大得多。?
? ? ? ? ? ? ? ? <form>表單元素的enctype屬性用于指定瀏覽器使用哪種編碼方法將表單中的數據傳送給WEB服務器,該屬性可以有兩種取值:
application/x-www-form-urlencoded multipart/form-data POST /servlet/ParamsServlet HTTP/1.1 Host: Content-Type: application/x-www-form-urlencoded Content-Length: 28param1=abc¶m2=xyz? ? ? ? ?get方式和post方式的區別:
? ? ? ? ?使用get方式提交表單時,瀏覽器將各個表單字段元素及其數據按照url參數的方式附加在請求行的資源后面。使用get方式傳遞的數據量是有限的,一般限制在1K以下。
? ? ? ? ?使用post方式時,瀏覽器把各表單字段元素及其數據作為HTTP消息的實體內容發送給web服務器,而不是作為url地址參數傳遞,因此,使用post方式,要比使用get方式大的多。 ? ??
? ? ? ? 1>get是從服務器上獲取數據,post是向服務器傳送數據。
? ? ? ? 2>在客戶端,Get方式在通過URL提交數據,數據在URL中可以看到;POST方式,數據放置在HTML HEADER內提交。
? ? ? ? 3>對于get方式,服務器端用Request.QueryString獲取變量的值,對于post方式,服務器端用Request.Form獲取提交的數據。
? ? ? ? 4>GET方式提交的數據最多只能有1024字節,而POST則沒有此限制。
? ? ? ? 5>安全性問題。正如在1>中提到,使用Get的時候,參數會顯示在地址欄上,而Post不會。所以,如果這些數據是中文數據而且是非敏感數據,那么使用get;如果用戶輸入的數據不是中文字符而且包含敏感數據,那么還是使用post為好。
? ? ? ? ?響應狀態碼
? ? ? ? ?響應狀態碼用于表示服務器對請求的各種不同處理結果和狀態,它是一個三位的十進制數。響應狀態碼可歸為5種類別,使用最高位為1到5來進行分類,如下所示:
? ? ? ? (1)100~199表示成功接收請求,要求客戶端繼續提交下一次請求才能完成整個處理過程 。(2)200~299表示成功接收請求并已完成整個處理過程 。(3)300~399為完成請求,客戶需進一步細化請求。例如,請求的資源已經移動一個新地址。(4)400~499客戶端的請求有錯誤。(5)500~599服務器端出現錯誤。
200(正常)表示一切正常,返回的是正常請求結果。206(部分內容)客戶發送了一個帶有Range頭(要求服務器只返回文檔中的部分內容)的GET請求,服務器按要求完成了這個請求。302/307(臨時重定向)指出被請求的文檔已被臨時移動到別處,此文檔的新的URL在Location響應頭中給出。304(未修改)表示客戶機緩存的版本是最新的,客戶機應該繼續使用它。 401(未經授權)表示客戶機訪問的是一個受口令和密碼保護的頁面,結合使用一個WWW-Authenticate響應頭提示客戶機應重新發出一個帶有Authorization頭的請求消息。404(找不到)服務器上不存在客戶機所請求的資源。500(內部服務器錯誤)服務器端的CGI、ASP、JSP等程序發生錯誤。? ? ? ??通用信息頭
? ? ? ? 通用信息頭字段既能用于請求消息,也能用于響應消息,它包括一些與被傳輸的實體內容沒有關系的常用消息頭字段。
Cache-Control: no-cache Connection: close/Keep-Alive Date: Tue, 11 Jul 2014 18:23:51 GMT Pragma: no-cache Trailer: Date Transfer-Encoding: chunked Upgrade: HTTP/2.0, SHTTP/1.3 Via: HTTP/1.1 Proxy1, HTTP/1.1 Proxy2 Warning: any text? ? ? ?請求頭
請求頭字段用于客戶端在請求消息中向服務器傳遞附加信息,主要包括客戶端可以接受的數據類型、壓縮方法、語言、以及發出請求的超鏈接所屬網頁的URL地址等信息。 Accept: text/html,image/* Accept-Charset: ISO-8859-1,unicode-1-1 Accept-Encoding: gzip,compress Accept-Language: en-gb,zh-cn Authorization: Basic enh4OjEyMzQ1Ng== Expect: 100-continue From: zxx@it315.org Host: www.it315.org:80 If-Match: "xyzzy", "r2d2xxxx" If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT If-None-Match: "xyzzy", "r2d2xxxx" If-Range: Tue, 11 Jul 2000 18:23:51 GMT If-Unmodified-Since: Tue, 11 Jul 2000 18:23:51 GMT Max-Forwards: 1 Proxy-Authorization: Basic enh4OjEyMzQ1Ng== Range: bytes=100-599 Range: bytes=100- Range: bytes=-100 Referer: http://www.it315.org/index.jsp TE: trailers,deflate User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)? ? ? ? ?響應頭
? ? ? ? ?響應頭字段用于服務器在響應消息中向客戶端傳遞附加信息,包括服務程序名,被請求資源需要的認證方式,被請求資源已移動到的新地址等信息。
Accept-Range: bytes Age: 315315315 Etag: b38b9-17dd-367c5dcd Location: http://www.it315.org/index.jsp Proxy-Authenticate: BASIC realm="it315" Retry-After: Tue, 11 Jul 2000 18:23:51 GMT Server: Microsoft-IIS/5.0 Vary: Accept-Language WWW-Authenticate: BASIC realm="it315"? ? ? ? 實體頭
實體頭用作實體內容的元信息,描述了實體內容的屬性,包括實體信息類型、長度、壓縮方法、最后一次修改時間、數據有效期等。 Allow: GET,POST Content-Encoding: gzip Content-Language: zh-cn Content-Length: 80 Content-Location: http://www.it315.org/java_cn.html Content-MD5: ABCDABCDABCDABCDABCDAB== Content-Range: bytes 2543-4532/7898 Content-Type: text/html; charset=GB2312 Expires: Tue, 11 Jul 2000 18:23:51 GMT Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT? ? ? ? 擴展頭
在HTTP消息中,也可以使用一些在HTTP 1.1正式規范里沒有定義的頭字段,這些頭字段統稱為自定義的HTTP頭或擴展頭,它們通常被當作是一種實體頭處理。現在流行的瀏覽器實際上都支持Cookie、Set-Cookie、Refresh和Content-Disposition等幾個常用的擴展頭字段。 //Refresh頭字段Refresh: 1 Refresh: 1;url=http://www.it315.org //Content-Disposition頭字段 Content-Type: application/octet-streamContent-Disposition: attachment; filename=aaa.zip? ? ? ?問題
HTTP協議是一種無狀態的協議,WEB服務器本身不能識別出哪些請求是同一個瀏覽器發出的 ,瀏覽器的每一次請求都是完全孤立的。即使 HTTP1.1 支持持續連接,但當用戶有一段時間沒有提交請求,連接也會關閉。 怎么才能實現網上商店中的購物車呢:某個用戶從網站的登錄頁面登入后,再進入購物頁面購物時,負責處理購物請求的服務器程序必須知道處理上一次請求的程序所得到的用戶信息。 作為 web 服務器,必須能夠采用一種機制來唯一地標識一個用戶,同時記錄該用戶的狀態。 會話和會話狀態? ? ? WEB應用中的會話是指一個客戶端瀏覽器與WEB服務器之間連續發生的一系列請求和響應過程。WEB應用的會話狀態是指WEB服務器與瀏覽器在會話過程中產生的狀態信息,借助會話狀態,WEB服務器能夠把屬于同一會話中的一系列的請求和響應過程關聯起來。
實現有狀態的會話
? ? ? WEB服務器端程序要能從大量的請求消息中區分出哪些請求消息屬于同一個會話,即能識別出來自同一個瀏覽器的訪問請求,這需要瀏覽器對其發出的每個請求消息都進行標識:屬于同一個會話中的請求消息都附帶同樣的標識號,而屬于不同會話的請求消息總是附帶不同的標識號,這個標識號就稱之為會話ID(SessionID)。在 Servlet 規范中,常用以下兩種機制完成會話跟蹤Cookie和Session。
?
cookie機制
? ? ? ?Cookie機制采用的是在客戶端保持 HTTP 狀態信息的方案。
? ? ? ?Cookie是在瀏覽器訪問WEB服務器的某個資源時,由WEB服務器在HTTP響應消息頭中附帶傳送給瀏覽器的一個小文本文件。一旦WEB瀏覽器保存了某個Cookie,那么它在以后每次訪問該WEB服務器時,都會在HTTP請求頭中將這個Cookie回傳給WEB服務器。
? ? ? ?底層的實現原理: WEB服務器通過在HTTP響應消息中增加Set-Cookie響應頭字段將Cookie信息發送給瀏覽器,瀏覽器則通過在HTTP請求消息中增加Cookie請求頭字段將Cookie回傳給WEB服務器。
一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和設置值(VALUE)。一個WEB站點可以給一個WEB瀏覽器發送多個Cookie,一個WEB瀏覽器也可以存儲多個WEB站點提供的Cookie。瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制為4KB。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? 在Servlet程序中使用Cookie
? ? ? ??Servlet API中提供了一個javax.servlet.http.Cookie類來封裝Cookie信息,它包含有生成Cookie信息和提取Cookie信息的各個屬性的方法。?
//Cookie類的方法: //構造方法: public Cookie(String name,String value) getName方法 setValue與getValue方法 setMaxAge與getMaxAge方法 setPath與getPath方法 HttpServletResponse接口中定義了一個addCookie方法,它用于在發送給瀏覽器的HTTP響應消息中增加一個Set-Cookie響應頭字段。 HttpServletRequest接口中定義了一個getCookies方法,它用于從HTTP請求消息的Cookie請求頭字段中讀取所有的Cookie項。 cookie的發送 1>.創建Cookie對象 2>.設置最大時效 3>.將Cookie放入到HTTP響應報頭 如果創建了一個cookie,并將他發送到瀏覽器,默認情況下它是一個會話級別的cookie; 存儲在瀏覽器的內存中,用戶退出瀏覽器之后被刪除。若希望瀏覽器將該cookie存儲在磁盤上,則需要使用maxAge,并給出一個以秒為單位的時間。將最大時效設為0則是命令瀏覽器刪除該cookie。發送cookie需要使用HttpServletResponse的addCookie方法,將cookie插入到一個 Set-Cookie HTTP響應報頭中。由于這個方法并不修改任何之前指定的Set-Cookie報頭,而是創建新的報頭,因此將這個方法稱為是addCookie,而非setCookie。 會話cookie和持久cookie的區別 如果不設置過期時間,則表示這個cookie生命周期為瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。這種生命期為瀏覽器會話期的cookie被稱為會話cookie。會話cookie一般不保存在硬盤上而是保存在內存里。如果設置了過期時間,瀏覽器就會把cookie保存到硬盤上,關閉后再次打開瀏覽器,這些cookie依然有效直到超過設定的過期時間。存儲在硬盤上的cookie可以在不同的瀏覽器進程間共享,比如兩個IE窗口。而對于保存在內存的cookie,不同的瀏覽器有不同的處理方式。 cookie的讀取 1>.調用request.getCookies,要獲取瀏覽器發送來的cookie,需要調用HttpServletRequest的getCookies方法,這個調用返回Cookie對象的數組,對應由HTTP請求中Cookie報頭輸入的值。 2>.對數組進行循環,調用每個cookie的getName方法,直到找到感興趣的cookie為止. 使用cookie屬性的注意問題 屬性是從服務器發送到瀏覽器的報頭的一部分;但它們不屬于由瀏覽器返回給服務器的報頭。因此除了名稱和值之外,cookie屬性只適用于從服務器輸出到客戶端的cookie;服務器端來自于瀏覽器的cookie并沒有設置這些屬性。 Session機制 Session機制采用的是在服務器端保持 HTTP 狀態信息的方案 。 服務器使用一種類似于散列表的結構(也可能就是使用散列表)來保存信息。當程序需要為某個客戶端的請求創建一個session時,服務器首先檢查這個客戶端的請求里是否包含了一個session標識(即sessionId),如果已經包含一個sessionId則說明以前已經為此客戶創建過session,服務器就按照session id把這個session檢索出來使用(如果檢索不到,可能會新建一個,這種情況可能出現在服務端已經刪除了該用戶對應的session對象,但用戶人為地在請求的URL后面附加上一個JSESSION的參數)。如果客戶請求不包含sessionId,則為此客戶創建一session 并且生成一個與此session相關聯的sessionId,這個session id將在本次響應中返回給客戶端保存。 保存session id的幾種方式 1>保存session id的方式可以采用cookie,這樣在交互過程中瀏覽器可以自動的按照規則把這個標識發送給服務器。 2>由于cookie可以被人為的禁用,必須有其它的機制以便在cookie被禁用時仍然能夠把session id傳遞回服務器,經常采用的一種技術叫做URL重寫,就是把session id附加在URL路徑的后面,附加的方式也有兩種,一種是作為URL路徑的附加信息,另一種是作為查詢字符串附加在URL后面。網絡在整個交互過程中始終保持狀態,就必須在每個客戶端可能請求的路徑后面都包含這個session id。 Session cookie 1>session通過SessionID來區分不同的客戶, session是以cookie或URL重寫為基礎的,默認使用cookie來實現,系統會創造一個名為JSESSIONID的輸出cookie,這稱之為session cookie,以區別persistent cookies(也就是我們通常所說的cookie),session cookie是存儲于瀏覽器內存中的,并不是寫到硬盤上的,通常看不到JSESSIONID,但是當把瀏覽器的cookie禁止后,web服務器會采用URL重寫的方式傳遞Sessionid,這時地址欄可看到; 2>session cookie針對某一次會話而言,會話結束session cookie也就隨著消失了,而persistent cookie只是存在于客戶端硬盤上的一段文本; 3>關閉瀏覽器,只會是瀏覽器端內存里的session cookie消失,但不會使保存在服務器端的session對象消失,同樣也不會使已經保存到硬盤上的持久化cookie消失。 Session的創建與刪除 一個常見的錯誤是以為session在有客戶端訪問時就被創建,然而事實是直到某server端程序(如Servlet)調用HttpServletRequest.getSession(true)這樣的語句時才會被創建。 session在下列情況下被刪除: 1>程序調用HttpSession.invalidate() 2>距離上一次收到客戶端發送的session id時間間隔超過了session的最大有效時間 3>服務器進程被停止 注意:關閉瀏覽器只會使存儲在客戶端瀏覽器內存中的session cookie失效,不會使服務器端的session對象失效。 ?兩個瀏覽器窗口訪問應用程序會使用同一個session 通常session cookie是不能跨窗口使用的,當你新開了一個瀏覽器窗口進入相同頁面時,系統會賦予你一個新的session id,這樣信息共享的目的就達不到了。 此時可以先把session id保存在persistent cookie中(通過設置cookie的最大有效時間),然后在新窗口中讀出來,就可以得到上一個窗口的session id了,這樣通過session cookie和persistent cookie的結合就可以實現了跨窗口的會話跟蹤。 Session的超時管理 WEB服務器無法判斷當前的客戶端瀏覽器是否還會繼續訪問,也無法檢測客戶端瀏覽器是否關閉,所以,即使客戶已經離開或關閉了瀏覽器,WEB服務器還要保留與之對應HttpSession對象。隨著時間的推移而不斷增加新的訪問客戶端,WEB服務器內存中將會因此積累起大量的不再被使用的HttpSession對象,并將最終導致服務器內存耗盡。WEB服務器采用“超時限制”的辦法來判斷客戶端是否還在繼續訪問,如果某個客戶端在一定的時間之內沒有發出后續請求,WEB服務器則認為客戶端已經停止了活動,結束與該客戶端的會話并將與之對應的HttpSession對象變成垃圾。如果客戶端瀏覽器超時后再次發出訪問請求,WEB服務器則認為這是一個新的會話的開始,將為之創建新的HttpSession對象和分配新的會話標識號。會話的超時間隔可以在web.xml文件中設置,其默認值由Servlet容器定義。 <session-config><session-timeout>30</session-timeout></session-config>? ? ? ?HttpSession接口中的方法
getId方法 getCreationTime方法 getLastAccessedTime方法 setMaxInactiveInterval方法 getMaxInactiveInterval方法 isNew方法 //如果客戶端請求消息中返回了一個與Servlet程序當前獲得的HttpSession對象的會話標識號相同的會話標識號,則認為這個HttpSession對象不是新建的。 invalidate方法 getServletContext方法 setAttribute方法 getAttribute方法 removeAttribute方法 getAttributeNames方法? ? ? ?HttpServletRequest接口中的Session方法
getSession方法 public HttpSession getSession(boolean?create) public HttpSession getSession() isRequestedSessionIdValid方法 isRequestedSessionIdFromCookie方法 isRequestedSessionIdFromURL方法? ? ? ?利用URL重寫實現Session跟蹤
Servlet規范中引入了一種補充的會話管理機制,它允許不支持Cookie的瀏覽器也可以與WEB服務器保持連續的會話。這種補充機制要求在響應消息的實體內容中必須包含下一次請求的超鏈接,并將會話標識號作為超鏈接的URL地址的一個特殊參數。 將會話標識號以參數形式附加在超鏈接的URL地址后面的技術稱為URL重寫。如果在瀏覽器不支持Cookie或者關閉了Cookie功能的情況下,WEB服務器還要能夠與瀏覽器實現有狀態的會話,就必須對所有可能被客戶端訪問的請求路徑(包括超鏈接、form表單的action屬性設置和重定向的URL)進行URL重寫。 HttpServletResponse接口中定義了兩個用于完成URL重寫方法:encodeURL方法encodeRedirectURL方法? ? ??application與Session域范圍的屬性?
?? ? ? ??Application與session域范圍的屬性比較?
HttpSession session = request.getSession(); Integer sessionCount = (Integer)session.getAttribute("count"); int count = 0; if(sessionCount != null) {count = sessionCount.intValue(); } out.println("當前會話中發生了" + (++count) + "次訪問<br>"); session.setAttribute("count",new Integer(count));count = 0; ServletContext application = getServletContext(); Integer applicationCount = (Integer)application.getAttribute("count"); if(applicationCount != null) {count = applicationCount.intValue(); } out.println("WEB應用程序中發生了" + (++count) + "次訪問<br>"); application.setAttribute("count",new Integer(count));? ? ? ?Session的典型案例
1>使用Session實現購物車;2>利用Session防止表單重復提交;3>利用Session實現一次性驗證碼? ? ? ?避免表單的重復提交:
? ? ? ?調用 RequestDispatcher.forward() 方法,瀏覽器所保留的URL 是先前的表單提交的 URL,此時點擊”刷新”, 瀏覽器將再次提交用戶先前輸入的數據,引起重復提交.如果采用 HttpServletResponse.sendRedirct() 方法將客戶端重定向到成功頁面,將不會出現重復一條問題.
? ? ? ?Js 客戶端避免表單重復提交,如下所示,其不足:當用戶單擊”刷新”,或單擊”后退”再次提交表單,將導致表單重復提交。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ??利用Session防止表單重復提交
? ? ? ??包含有FORM表單的頁面必須通過一個服務器程序動態產生,服務器程序為每次產生的頁面中的FORM表單都分配一個唯一的隨機標識號,并在FORM表單的一個隱藏字段中設置這個標識號,同時在當前用戶的Session域中保存這個標識號。當用戶提交FORM表單時,負責接收這一請求的服務器程序比較FORM表單隱藏字段中的標識號與存儲在當前用戶的Session域中的標識號是否相同,如果相同則處理表單數據,處理完后清除當前用戶的Session域中存儲的標識號。
? ? ? ? 在下列情況下,服務器程序將忽略提交的表單請求:
1>當前用戶的Session中不存在表單標識號; 2>用戶提交的表單數據中沒有標識號字段; 3>存儲在當前用戶的Session域中的表單標識號與表單數據中的標識號不同. 瀏覽器只有重新向WEB服務器請求包含FORM表單的頁面時,服務器程序才又產生另外一個隨機標識號,并將這個標識號保存在Session域中和作為新返回的FORM表單中的隱藏字段值。? ? ? ??TokenProcessor.java:用于管理表單標識號的工具類,它主要用于產生、比較和清除存儲在當前用戶Session中的表單標識號。為了保證表單標識號的唯一性,每次將當前SessionID和系統時間的組合值按MD5算法計算的結果作為表單標識號,并且將TokenProcessor類設計為單件類.
? ? ? ??問題:
? ? ? ? ? ? ? 同一個用戶打開同一個瀏覽器進程的多個窗口來并發訪問同一個WEB站點的多個FORM表單頁面時,將會出現表單無法正常提交的情況。
解決方案: 將FORM表單的標識號作為表單隱藏字段的名稱,如下所示: <input type='hidden' name='4b15c6b2f573831b4b5107d849fcafb8' value=''>? ? ? ? ? ? 將所有的表單標識號存儲進一個Vector集合對象中,并將Vector集合對象存儲進Session域中。當表單提交時,先從Session域中取出Vector集合對象,然后再從Vector集合對象中逐一取出每個表單標識號作為參數調用HttpServletRequest.getParameter方法,如果其中有一次調用的返回值不為null,則接受并處理該表單數據,處理完后將該表單標識號從Vector集合對象中刪除。
? ? ? ?利用Session實現一次性驗證碼?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
一次性驗證碼的主要目的就是為了限制人們利用工具軟件來暴力猜測密碼,其原理與利用Session防止表單重復提交的原理基本一樣,只是將表單標識號變成了驗證碼的形式,并且要求用戶將提示的驗證碼手工填寫進一個表單字段中,而不是通過表單的隱藏字段自動回傳給服務器。 服務器程序接收到表單數據后,首先判斷用戶是否填寫了正確的驗證碼,只有該驗證碼與服務器端保存的驗證碼匹配時,服務器程序才開始正常的表單處理流程。密碼猜測工具要逐一嘗試每個密碼的前題條件是先輸入正確的驗證碼,而驗證碼是一次性有效的,這樣基本上就阻斷了密碼猜測工具的自動地處理過程。?
?
轉載于:https://www.cnblogs.com/Vae1990Silence/p/4699973.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的java_web学习(8)会话与状态管的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring和mybatis整合进行事务
- 下一篇: 第一个简单的DEMO