Cookie是一種在客戶端儲存資訊的技術,通過Cookie可以向客戶端寫入和讀取訊息。還可以通過編碼的方式向Cookie中寫入複雜資料,如被序列化的物件例項、影象等。
一、什麼是Cookie
在瀏覽網頁的時候可能會注意到這樣的現象,如在開啟某個登入網頁時,第一次開啟時,使用者名稱文字框是空的。當輸入一個使用者名稱併成功登入後,第二次開啟這個登入網頁時,第一次輸入的使用者名稱會被自動填入這個使用者名稱文字框,就算重啟計算機後,仍然如此。其實,這就是Cookie所起的作用。由於HTTP協議是無狀態的,因此他是不可能儲存這個歌使用者名稱的。那麼這種可能就是在第一次登入後,將這個使用者名稱儲存在了客戶端硬碟的某個地方。當再次訪問這個頁面的時候,瀏覽器會根據這個儲存在客戶端硬碟上的使用者名稱或標識知道這個使用者曾經訪問過這個頁面,並對這個使用者做進一步的處理。這個被儲存的使用者名稱或使用者標識就被稱為一個Cookie。Cookie是在瀏覽器訪問某個Web資源時,由Web伺服器在HTTP響應訊息頭中通過Set-Cookie欄位傳送給瀏覽器的一組訊息。
瀏覽器會根據Set-Cookie欄位中的Cookie資料決定是否儲存這些Cookie。當瀏覽器下一次訪問這個Web資源時,會自動讀取這些被儲存的Cookie,並加到HTTP請求訊息頭的Cookie欄位中,Web伺服器會根據Cookie欄位的內容作出相應的處理。如上述的使用者名稱資訊將使用Cookie欄位傳送到Web伺服器,然後Web伺服器會獲得這個使用者名稱,並做進一步處理。
一個Cookie值表示一個key-value鍵值對,這個key-value對由Cookie名和Cookie值組成。Web伺服器可以給一個Web瀏覽器傳送多個Cookie,但每個Cookie的大小一般被限制為4KB。在Servlet API 中,使用java.servlet.http.Cookie類來封裝一個Cookie訊息,在HttpServletResponse介面中定義了一個addCookie()方法來向瀏覽器傳送Cookie物件,在HttpServletRequest介面中定義了一個getCookies()方法來讀取瀏覽器傳遞過來的Cookie訊息。Cookie類中定義了生成和獲取Cookie訊息的各個屬性的方法。Cookie類只有一個構造方法:
public Cookie(String name,String value)
其中name表示Cookie名(在name引數值中不能包含任何空格字元、逗號、分號,並且不能以$字元開頭),value表示Cookie 的值。Cookie類的其它常用方法:
- getName():該方法返回Cookie 的名稱。
- setValue()和getValue() :這兩個方法分別用於設定和獲取Cookie的值。
- setMaxAge()和getMaxAge() :這兩個方法分別用於設定和獲取Cookie在客戶端的有效時間(以秒為單位)。如果設定為0,表示當Cookie訊息傳送到客戶端瀏覽器時被立即刪除。如果設定為負數,表示瀏覽器並不會把這個Cookie儲存在硬碟上,這種Cookie被稱為臨時Cookie(儲存在硬碟上的Cookie被稱為永久Cookie),它們只存在於當前瀏覽器的程式中,當瀏覽器關閉後,Cookie自動失效。對於IE瀏覽器,不同的視窗不能共享臨時Cookie,但按Ctrl+N快捷鍵或使用JavaScript的window.open語句開啟的視窗由於和它們的父視窗屬於同一個瀏覽器程式,因此它們可以共享臨時Cookie。而在FireFox中,所有的程式和標籤頁都可以共享臨時Cookie。
- setPath和getPath方法:這兩個方法分別用於設定和獲取當前Cookie的有效Web路徑。如果在建立某個Cookie時為設定它的path屬性,那麼該Cookie只對當前訪問的Servlet所在的Web路徑及其子路徑有效。如果想使Cookie對整個Web站點中的所有可訪問的路徑都有效,需要將path屬性值設定為"/" 。
- setComment和getComment方法:這兩個方法分別用於設定和獲取當前Cookie 的註釋部分。
- setVersion和getVersion方法:這兩個方法分別用於設定和獲取當前Cookie的協議版本。
- setSecure和getSecure方法:這兩個方法分別用於設定和獲取當前Cookie是否只能使用安全的協議傳輸Cookie。
下面演示如何在Servlet中使用Cookie。其中SaveCookie類負責向客戶端瀏覽器寫入3種Cookie:永久Cookie、臨時Cookie 和有效時間為0 的Cookie:
import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SaveCookie extends HttpServlet { /** * */ private static final long serialVersionUID = -8265745579634360083L; protected void service(HttpServletRequest request ,HttpServletResponse response) throws ServletException , IOException{ response.setContentType("text/html; charset=UTF-8 "); //PrintWriter out = response.getWriter() ; Cookie tempCookie = new Cookie("temp","87654321"); //建立臨時Cookie,不設定setMaxAge屬性 response.addCookie(tempCookie); //新增臨時Cookie物件 //建立有效時間為0 的Cookie Cookie cookie = new Cookie("cookie" , "6666") ; cookie.setMaxAge(0); response.addCookie(cookie); //獲取請求引數User的值 String user = request.getParameter("user") ; if(user!=null){ Cookie userCookie = new Cookie("user" , user) ; userCookie.setMaxAge(3600); userCookie.setPath("/"); // 這個Cookie對站點中所有目錄下的訪問路徑都有效 response.addCookie(userCookie); } // response.sendRedirect("ReadCookie"); RequestDispatcher readCookie = getServletContext().getRequestDispatcher("/servlet/ReadCookie") ; readCookie.include(request, response); } }
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ReadCookie extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; protected Cookie getCookieValue(Cookie[] cookies , String name){ if(cookies!=null){ for(Cookie c :cookies){ if(c.getName().equals(name)){ return c ; } } } return null ; } public void service(HttpServletRequest request ,HttpServletResponse response) throws ServletException , IOException{ response.setContentType("text/html ;charset=UTF-8"); PrintWriter out = response.getWriter() ; Cookie tempCookie =getCookieValue(request.getCookies(),"temp"); if(tempCookie != null){ out.println("臨時Cookie值:"+tempCookie.getValue()+"<br>"); }else { out.print("臨時Cookie未設定!<br>"); } Cookie cookie = getCookieValue(request.getCookies(),"cookie"); if(cookie!=null){ out.println("cookie:"+cookie.getValue()+"<br>"); }else { out.println("cookie已經被刪除!<br>"); } Cookie userCookie = getCookieValue(request.getCookies(),"user"); if(userCookie !=null){ out.println("user:"+userCookie.getValue()); }else { out.println("user未設定!"); } } }
解決Cookie亂碼問題,即使在開頭設定了request和response的中文編碼格式,直接在Cookie的引數值中儲存中文字元會出現亂碼或者執行錯誤,需要使用java.net.URLEncoder類的encode()方法對有中文引數的變數接受時進行編碼處理,再放入建立的Cookie物件中作為引數值:
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html ; charset=utf-8");
String username =URLEncoder.encode(request.getParameter("cname"), "utf-8") ; //username中有中文!
//String username = request.getParameter("cname") ;
String password = request.getParameter("psd") ;
String rememberme = request.getParameter("rememberme");
System.out.println(username);
System.out.println(password);
System.out.println(rememberme);
if(username!=null&&username.trim().length()>0&&password!=null&&password.trim().length()>0){
if(rememberme!=null&&rememberme.trim().length()>0){
Cookie[] ck = request.getCookies();
for(Cookie c: ck){
System.out.println(c.getName());
}
Cookie c_username = new Cookie("username",username);
Cookie c_password = new Cookie("password",password) ;
c_username.setMaxAge(3600);
c_password.setMaxAge(3600);
response.addCookie(c_username);
response.addCookie(c_password);
System.out.println("Cookie已經新增!");
}
然後接收Cookie後在使用Cookie裡的引數值前,需要將有中文的那個引數值再解碼,使用java.net.URLDecoder類的decode()方法解碼,然後再使用這個引數值,便可正確顯示。
<body>
<%
String username = "" ;
String password = "" ;
Cookie[] cs = request.getCookies();
if(cs!=null){
//out.print("Cookie已經存在! ");
for(Cookie c: cs){
if("username".equals(c.getName())){
username = c.getValue();
}
if("password".equals(c.getName())){
password = c.getValue();
}
}
}
%>
<form action="LoginServlet" method="post">
<table>
<tr><td>使用者名稱:</td><td><input type="text" name="cname" value="<%=URLDecoder.decode(username, "utf-8")%>"/></td></tr>
<tr><td>密碼:</td><td><input type="password" name="psd" value="<%=password%>"/></td></tr>
<tr><td colspan="2"><input type="checkbox" name="rememberme" value="do"/></td></tr>
<tr><td><input type="submit" value="提交"/></td></tr>
</table>
</form>
</body>
</html>