首先,Session與Cookie的作用都是爲了保持訪問用戶與後端服務器的交互狀態,也就是跟蹤用戶的整個會話。不同的是,Cookie通過在客戶端記錄信息確定用戶身份,Session通過在服務器端記錄信息確定用戶身份。
一、理解Cookie
1、Cookie爲什麼會出現?
2、Cookie的屬性項
屬性項 | 屬性項介紹 |
---|---|
NAME=VALUE | 鍵值對,可以設置要保存的Key/Value,注意這裏的NAME不能和其他屬性項的名字一樣 |
Expires | 過期時間,在設置的某個時間點後該Cookie就會失效,如expires=Wednesday,16-Nov-17 23:12:40 GMT |
Max-Age | 最大失效時間,表示在多少秒後失效 |
Domain | 生成該Cookie的域名,即可以訪問該Cookie的域名 |
Path | 生成該Cookie的路徑,即可以訪問該Cookie的路徑,設置爲“/”,則本域名下contextPath都可以訪問該Cookie,最後一個字符必須爲“/” |
Secure | 如果設置了這個屬性,那麼只會在使用安全協議連接時纔會回傳該Cookie,安全協議有HTTPS,SSL等。默認爲false。 |
Comment | 註釋項,說明該Cookie有何用途 |
Version | 該Cookie的版本號。0表示遵循Netscape的Cookie規範,1表示遵循W3C的RFC 2109規範 |
Port | 該Cookie在什麼端口下可以回傳服務端,如果有多個端口,用逗號隔開 |
Discard | 是否在會話結束後丟棄該Cookie項,默認爲false |
下面詳細介紹Cookie的這些屬性項:
2.1 Cookie的有效期
response對象提供的Cookie操作方法只有一個添加操作add(Cookie cookie)。要想修改Cookie只能使用一個同名的Cookie來覆蓋原來的Cookie。
刪除時只需要把maxAge修改爲0即可。
注意:
(1)從客戶端讀取Cookie時,包括maxAge在內的其他屬性都是不可讀的,也不會被提交。瀏覽器提交Cookie時只會提交name與value屬性。
maxAge屬性只被瀏覽器用來判斷Cookie是否過期。
(2)修改、刪除Cookie時,新建的Cookie除value、maxAge之外的所有屬性,例如name、path、domain等,都要與原Cookie完全一樣。否則,
瀏覽器將視爲兩個不同的Cookie不予覆蓋,導致修改、刪除失敗。
2.2 Cookie的域名
Cookie是不可跨域名的。域名www.google.com頒發的Cookie不會被提交到域名www.baidu.com去。這是由Cookie的隱私安全機制決定的。隱私安全機制能夠禁止網站非法獲取其他網站的Cookie。
Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setDomain(".helloweenvsfei.com"); // 設置域名
cookie.setPath("/"); // 設置路徑
cookie.setMaxAge(Integer.MAX_VALUE); // 設置有效期
response.addCookie(cookie); // 輸出到客戶端
可以修改本機C:\WINDOWS\system32\drivers\etc下的hosts文件來配置多個臨時域名,然後使用setCookie.jsp程序來設置跨域名Cookie驗證domain屬性。
注意:domain參數必須以點(".")開始。另外,name相同但domain不同的兩個Cookie是兩個不同的Cookie。如果想要兩個域名完全不同的網站共有Cookie,可以生成兩個Cookie,domain屬性分別爲兩個域名,輸出到客戶端。
正常情況下,同一個一級域名下的兩個二級域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能交互使用Cookie,因爲二者的域名並不嚴格相同。如果想所有helloweenvsfei.com名下的二級域名都可以使用該Cookie,需要設置Cookie的domain參數,例如:
2.3 Cookie的路徑
domain屬性決定運行訪問Cookie的域名,而path屬性決定允許訪問Cookie的路徑(ContextPath)。例如,如果只允許/session/下的程序使用Cookie,可以這麼寫:
Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setPath("/session/"); // 設置路徑
response.addCookie(cookie); // 輸出到客戶端
設置爲“/”時允許所有路徑使用Cookie。path屬性需要使用符號“/”結尾。name相同但path不相同的兩個Cookie也是兩個不同的Cookie。注意:頁面只能獲取它屬於的Path的Cookie。例如/session/test/a.jsp不能獲取到路徑爲/session/abc/的Cookie。
2.4 Cookie的安全屬性
cookie.setSecure(true); // 設置安全屬性
response.addCookie(cookie); // 輸出到客戶端
3、Cookie的字符編碼
3.1 Unicode編碼:保存中文
中文與英文字符不同,中文屬於Unicode字符,在內存中佔4個字符,而英文屬於ASCII字符,內存中只佔2個字節。Cookie中使用Unicode字符時需要對Unicode字符進行編碼,否則會亂碼。
注意:Cookie中保存中文只能編碼。一般使用UTF-8編碼即可。不推薦使用GBK等中文編碼,因爲瀏覽器不一定支持,而且JavaScript也不支持GBK編碼。
3.2 BASE64編碼:保存二進制文件
4、Cookie的壓縮
//壓縮
private void compressCookie(Cookie c,HttpServletResponse res){
try{
ByteArrayOutputStream bos = null;
bos = new ByteArrayOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(bos);
dos.write(c.getValue().getBytes());
dos.close();
System.out.println("before compress length:" + c.getValue().getBytes().length);
String compress = new sum.misc.BASE64Encoder().encode(bos.toByteArray());
res.addCookie(new Cookie("compress",compress));
System.out.println("after compress length:" + compress.getBytes().length);
}catch(IOException e){
e.printStackTrace();
}
}
//解壓縮
private void unCompressCookie(Cookie c){
try{
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] compress = new sun.misc.BASE64Decoder().decodeBuffer(new String(c.getValue().getBytes()));
ByteArrayInputStream bis = new ByteArrayInputStream(compress);
InflaterInputStream inflater = new InflaterInputStream(bis);
byte[] b = new byte[1024];
int count;
while((count = inflater.read(b)) >= 0){
out.write(b,0,count);
}
inflater.close();
System.out.println(out.toByteArray());
}catch(Exception e){
e.printStackTrace();
}
}
5、Cookie是如何工作的?
String getCookie(Cookie[] cookies,String key){
if(cookies != null){
for(Cookie cookie: cookies){
if(cookie.getName().equals(key))
return cookie.getValue();
}
}
return null;
}
@Override
public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
Cookie[] cookies = request.getCookies();
String username = getCookie(cookies,"username");
String userAge = getCookie(cookies,"userAge");
if(username == null)
response.addCookie(new Cookie("username","aaa"));
if(userAge == null)
response.addCookie(new Cookie("userAge","17"));
response.getHeaders("Set-Cookie");
}
Cookie是如何加到HTTP的Header中的呢?如下圖是Tomcat創建Set-Cookie響應頭的時序圖: