Cookie的目的就是為用戶帶來方便,為網站帶來增值。雖然有著許多誤傳,事實上Cookie并不會造成嚴重的安全威脅。Cookie永遠不會以任何方式執行,因此也不會帶來病毒或攻擊你的系統。另外,由于瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制為4?KB,因此Cookie不會塞滿你的硬盤,更不會被用作“拒絕服務”攻擊手段。?
???
?? ?9.2?Servlet的Cookie?API?
???
?? ?要把Cookie發送到客戶端,Servlet先要調用new?Cookie(name,value)用合適的名字和值創建一個或多個Cookie(2.1節),通過cookie.setXXX設置各種屬性(2.2節),通過response.addCookie(cookie)把cookie加入應答頭(2.3節)。?
???
?? ?要從客戶端讀入Cookie,Servlet應該調用request.getCookies(),getCookies()方法返回一個Cookie對象的數組。在大多數情況下,你只需要用循環訪問該數組的各個元素尋找指定名字的Cookie,然后對該Cookie調用getValue方法取得與指定名字關聯的值,這部分內容將在2.4節討論。?
???
?? ?9.2.1?創建Cookie?
???
?? ?調用Cookie對象的構造函數可以創建Cookie。Cookie對象的構造函數有兩個字符串參數:Cookie名字和Cookie值。名字和值都不能包含空白字符以及下列字符:?
???[?]?(?)?=?,?"?/???@?:?;?
???
???
???
???
?? ?9.2.2?讀取和設置Cookie屬性?
???
?? ?把Cookie加入待發送的應答頭之前,你可以查看或設置Cookie的各種屬性。下面摘要介紹這些方法:?
???
??getComment/setComment?
??獲取/設置Cookie的注釋。?
??getDomain/setDomain?
??獲取/設置Cookie適用的域。一般地,Cookie只返回給與發送它的服務器名字完全相同的服務器。使用這里的方法可以指示瀏覽器把Cookie返回給同一域內的其他服務器。注意域必須以點開始(例如.sitename.com),非國家類的域(如.com,.edu,.gov)必須包含兩個點,國家類的域(如.com.cn,.edu.uk)必須包含三個點。?
??getMaxAge/setMaxAge?
??獲取/設置Cookie過期之前的時間,以秒計。如果不設置該值,則Cookie只在當前會話內有效,即在用戶關閉瀏覽器之前有效,而且這些Cookie不會保存到磁盤上。參見下面有關LongLivedCookie的說明。?
??getName/setName?
??獲取/設置Cookie的名字。本質上,名字和值是我們始終關心的兩個部分。由于HttpServletRequest的getCookies方法返回的是一個Cookie對象的數組,因此通常要用循環來訪問這個數組查找特定名字,然后用getValue檢查它的值。?
??getPath/setPath?
??獲取/設置Cookie適用的路徑。如果不指定路徑,Cookie將返回給當前頁面所在目錄及其子目錄下的所有頁面。這里的方法可以用來設定一些更一般的條件。例如,someCookie.setPath("/"),此時服務器上的所有頁面都可以接收到該Cookie。?
??getSecure/setSecure?
??獲取/設置一個boolean值,該值表示是否Cookie只能通過加密的連接(即SSL)發送。?
??getValue/setValue?
??獲取/設置Cookie的值。如前所述,名字和值實際上是我們始終關心的兩個方面。不過也有一些例外情況,比如把名字作為邏輯標記(也就是說,如果名字存在,則表示true)。?
??getVersion/setVersion?
??獲取/設置Cookie所遵從的協議版本。默認版本0(遵從原先的Netscape規范);版本1遵從RFC?2109?,?但尚未得到廣泛的支持。?
?? ?9.2.3?在應答頭中設置Cookie?
???
?? ?Cookie可以通過HttpServletResponse的addCookie方法加入到Set-Cookie應答頭。下面是一個例子:?
???Cookie?userCookie?=?new?Cookie("user",?"uid1234");?
???response.addCookie(userCookie);?
???
???
???
???
?? ?9.2.4?讀取保存到客戶端的Cookie?
???
?? ?要把Cookie發送到客戶端,先要創建Cookie,然后用addCookie發送一個Set-Cookie?HTTP應答頭。這些內容已經在上面的2.1節介紹。從客戶端讀取Cookie時調用的是HttpServletRequest的getCookies方法。該方法返回一個與HTTP請求頭中的內容對應的Cookie對象數組。得到這個數組之后,一般是用循環訪問其中的各個元素,調用getName檢查各個Cookie的名字,直至找到目標Cookie。然后對這個目標Cookie調用getValue,根據獲得的結果進行其他處理。?
???
?? ?上述處理過程經常會遇到,為方便計下面我們提供一個getCookieValue方法。只要給出Cookie對象數組、Cookie名字和默認值,getCookieValue方法就會返回匹配指定名字的Cookie值,如果找不到指定Cookie,則返回默認值。?
???
?? ?9.3?幾個Cookie工具函數?
???
?? ?下面是幾個工具函數。這些函數雖然簡單,但是,在和Cookie打交道的時候很有用。?
???
?? ?9.3.1?獲取指定名字的Cookie值?
???
?? ?該函數是ServletUtilities.java的一部分。getCookieValue通過循環依次訪問Cookie對象數組的各個元素,尋找是否有指定名字的Cookie,如找到,則返回該Cookie的值;否則,返回參數中給出的默認值。getCookieValue能夠在一定程度上簡化Cookie值的提取。?
???public?static?String?getCookieValue(Cookie[]?cookies,?
???String?cookieName,?
???String?defaultValue)?{?
???for(int?i=0;?i<cookies.length;?i++)?{?
???Cookie?cookie?=?cookies[i];?
???if?(cookieName.equals(cookie.getName()))?
???return(cookie.getValue());?
???}?
???return(defaultValue);?
???}?
???
???
???
???
?? ?9.3.2自動保存的Cookie?
???
?? ?下面是LongLivedCookie類的代碼。如果你希望Cookie能夠在瀏覽器退出的時候自動保存下來,則可以用這個LongLivedCookie類來取代標準的Cookie類。?
??package?hall;?
???
??import?javax.servlet.http.*;?
???
??public?class?LongLivedCookie?extends?Cookie?{?
???public?static?final?int?SECONDS_PER_YEAR?=?60*60*24*365;?
???public?LongLivedCookie(String?name,?String?value)?{?
???super(name,?value);?
???setMaxAge(SECONDS_PER_YEAR);?
???}?
??}?
???
???
???
???
?? ?9.4.實例:定制的搜索引擎界面?
???
?? ?下面也是一個搜索引擎界面的例子,通過修改前面HTTP狀態代碼的例子得到。在這個Servlet中,用戶界面是動態生成而不是由靜態HTML文件提供的。Servlet除了負責讀取表單數據并把它們發送給搜索引擎之外,還要把包含表單數據的Cookie發送給客戶端。以后客戶再次訪問同一表單時,這些Cookie的值將用來預先填充表單,使表單自動顯示最近使用過的數據。?
???
?? ?SearchEnginesFrontEnd.java?
???
?? ?該Servlet構造一個主要由表單構成的用戶界面。第一次顯示的時候,它和前面用靜態HTML頁面提供的界面差不多。然而,用戶選擇的值將被保存到Cookie(本頁面將數據發送到CustomizedSearchEngines?Servlet,由后者設置Cookie)。用戶以后再訪問同一頁面時,即使瀏覽器是退出之后再啟動,表單中也會自動填好上一次搜索所填寫的內容。?
???
?? ?注意該Servlet用到了ServletUtilities.java,其中getCookieValue前面已經介紹過,headWithTitle用于生成HTML頁面的一部分。另外,這里也用到了前面已經說明的LongLiveCookie類,我們用它來創建作廢期限很長的Cookie。?
??package?hall;?
???
??import?java.io.*;?
??import?javax.servlet.*;?
??import?javax.servlet.http.*;?
??import?java.net.*;?
???
??public?class?SearchEnginesFrontEnd?extends?HttpServlet?{?
???public?void?doGet(HttpServletRequest?request,?
???HttpServletResponse?response)?
???throws?ServletException,?IOException?{?
???Cookie[]?cookies?=?request.getCookies();?
???String?searchString?=?
???ServletUtilities.getCookieValue(cookies,?
???"searchString",?
???"Java?Programming");?
???String?numResults?=?
???ServletUtilities.getCookieValue(cookies,?
???"numResults",?
???"10");?
???String?searchEngine?=?
???ServletUtilities.getCookieValue(cookies,?
???"searchEngine",?
???"google");?
???response.setContentType("text/html");?
???PrintWriter?out?=?response.getWriter();?
???String?title?=?"Searching?the?Web";?
???out.println(ServletUtilities.headWithTitle(title)?+?
???"<BODY?BGCOLOR=\"#FDF5E6\">\n"?+?
???"<H1?ALIGN=\"CENTER\">Searching?the?Web</H1>\n"?+?
???"\n"?+?
???"<FORM?ACTION=\"/servlet/hall.CustomizedSearchEngines\">\n"?+?
???"<CENTER>\n"?+?
???"Search?String:\n"?+?
???"<INPUT?TYPE=\"TEXT\"?NAME=\"searchString\"\n"?+?
???"?VALUE=\""?+?searchString?+?"\"><BR>\n"?+?
???"Results?to?Show?Per?Page:\n"?+?
???"<INPUT?TYPE=\"TEXT\"?NAME=\"numResults\"\n"?+?
???"?VALUE="?+?numResults?+?"?SIZE=3><BR>\n"?+?
???"<INPUT?TYPE=\"RADIO\"?NAME=\"searchEngine\"\n"?+?
???"?VALUE=\"google\""?+?
???checked("google",?searchEngine)?+?">\n"?+?
???"Google?|\n"?+?
???"<INPUT?TYPE=\"RADIO\"?NAME=\"searchEngine\"\n"?+?
???"?VALUE=\"infoseek\""?+?
???checked("infoseek",?searchEngine)?+?">\n"?+?
???"Infoseek?|\n"?+?
???"<INPUT?TYPE=\"RADIO\"?NAME=\"searchEngine\"\n"?+?
???"?VALUE=\"lycos\""?+?
???checked("lycos",?searchEngine)?+?">\n"?+?
???"Lycos?|\n"?+?
???"<INPUT?TYPE=\"RADIO\"?NAME=\"searchEngine\"\n"?+?
???"?VALUE=\"hotbot\""?+?
???checked("hotbot",?searchEngine)?+?">\n"?+?
???"HotBot\n"?+?
???"<BR>\n"?+?
???"<INPUT?TYPE=\"SUBMIT\"?VALUE=\"Search\">\n"?+?
???"</CENTER>\n"?+?
???"</FORM>\n"?+?
???"\n"?+?
???"</BODY>\n"?+?
???"</HTML>\n");?
???}?
???
???private?String?checked(String?name1,?String?name2)?{?
???if?(name1.equals(name2))?
???return("?CHECKED");?
???else?
???return("");?
???}?
??}?
???
???
???
???
?? ?CustomizedSearchEngines.java?
???
?? ?前面的SearchEnginesFrontEnd?Servlet把數據發送到CustomizedSearchEngines?Servlet。本例在許多方面與前面介紹HTTP狀態代碼時的例子相似,區別在于,本例除了要構造一個針對搜索引擎的URL并向用戶發送一個重定向應答之外,還要發送保存用戶數據的Cookies。?
??package?hall;?
???
??import?java.io.*;?
??import?javax.servlet.*;?
??import?javax.servlet.http.*;?
??import?java.net.*;?
???
??public?class?CustomizedSearchEngines?extends?HttpServlet?{?
???public?void?doGet(HttpServletRequest?request,?
???HttpServletResponse?response)?
???throws?ServletException,?IOException?{?
???
???String?searchString?=?request.getParameter("searchString");?
???Cookie?searchStringCookie?=?
???new?LongLivedCookie("searchString",?searchString);?
???response.addCookie(searchStringCookie);?
???searchString?=?URLEncoder.encode(searchString);?
???String?numResults?=?request.getParameter("numResults");?
???Cookie?numResultsCookie?=?
???new?LongLivedCookie("numResults",?numResults);?
???response.addCookie(numResultsCookie);?
???String?searchEngine?=?request.getParameter("searchEngine");?
???Cookie?searchEngineCookie?=?
???new?LongLivedCookie("searchEngine",?searchEngine);?
???response.addCookie(searchEngineCookie);?
???SearchSpec[]?commonSpecs?=?SearchSpec.getCommonSpecs();?
???for(int?i=0;?i<commonSpecs.length;?i++)?{?
???SearchSpec?searchSpec?=?commonSpecs[i];?
???if?(searchSpec.getName().equals(searchEngine))?{?
???String?url?=?
???searchSpec.makeURL(searchString,?numResults);?
???response.sendRedirect(url);?
???return;?
???}?
???}?
???response.sendError(response.SC_NOT_FOUND,?
???"No?recognized?search?engine?specified.");?
???}?
???
???public?void?doPost(HttpServletRequest?request,?
???HttpServletResponse?response)?
???throws?ServletException,?IOException?{?
???doGet(request,?response);?
???}?
??}?
posted on 2006-06-15 11:04
我心依舊 閱讀(1492)
評論(0) 編輯 收藏