iT邦幫忙

2021 iThome 鐵人賽

DAY 19
1

Cookie 介紹

Cookie 指得是儲存在Client (用戶)端上的資料,是一種在伺服器與瀏覽器之間交換訊息的方法,按照Client 端儲存的位置可分為記憶體Cookie 和硬碟Cookie。

記憶體Cookie 由瀏覽器維護,儲存在記憶體中,瀏覽器關閉即消失,存在時間短暫,也稱為非持久Cookie;硬碟Cookie 儲存在硬碟裡,有過期時間,除非使用者手動清理或到了過期時間,否則硬碟Cookie 不會清除,存在時間較長,也稱為為持久Cookie。

用途

因為HTTP 協定是無狀態的,Server 不知道使用者上一次做了什麼,這嚴重阻礙了互動式Web 應用程式的實現,所以Cookie 就是用來繞開HTTP 的無狀態性的一種手段,Server 可以設定或讀取Cookie 中包含的資訊,藉此維護使用者跟Server 對談中的狀態。

缺點

  1. Cookie 會附加在每個HTTP 請求中,無形中增加了傳輸流量。
  2. 由於HTTP 請求中的Cookie 是明文傳遞的,會造成安全性問題,除非使用超文字傳輸安全協定。
  3. Cookie 的大小限制在4KB 左右,對於複雜的儲存需求來說是不夠用的。

Cookie 實作

設置Cookie

若要在Spring Boot 中設置Cookie,就要使用到HttpServletResponseaddCookie() 方法,該方法就是將一個Cookie 物件加入Response 中。

@RequestMapping(value = "/setCookie", method = RequestMethod.GET)
public String setCookie(HttpServletResponse response) {

	// 建立一個Cookie 物件
	Cookie cookie = new Cookie("username", "kaijun");

	// 設置過期時間,若無設置時間,其生命週期將持續到Session 過期為止
	cookie.setMaxAge(7*24*60*60);

	// 將Cookie 物件加入Response 中
	response.addCookie(cookie);
	
	return "add Cookie";
}

讀取Cookie

Spring 框架提供了@CookieValue 註釋來取得Cookie 的值,其參數 value 為Cookie 名稱,可使用參數 defaultValue 設定預設值,若沒有預設值也查無Cookie 名稱則會拋出IllegalStateException 例外。

@RequestMapping(value = "/getCookie", method = RequestMethod.GET)
public String getCookie(@CookieValue(value = "username") String username) {
	
	return "Hello! " + username;
}

讀取所有Cookie

在實務上我們可能不只有一個Cookie,若要使用@CookieValue 一個一個取得會使得程式碼變得冗長,所以可以使用HttpServletRequestgetCookies() 方法一次取得所有Cookie。

@RequestMapping(value = "/getCookies", method = RequestMethod.GET)
public String getCookies(HttpServletRequest request) {

	Cookie[] cookies = request.getCookies();
		if (cookies != null) {
		return Arrays.stream(cookies)
			.map(c -> c.getName() + "=" + c.getValue())
			.collect(Collectors.joining(", "));
	}
	return "No cookies";
}

HTTPS 與Cookie

我們可以指定Cookie 僅能透過加密的HTTPS 連結發送Cookie 到伺服器,無法透過未加密的HTTP 連接傳送。

// 改寫上面setCookie 方法
@RequestMapping(value = "/setCookie", method = RequestMethod.GET)
public String setCookie(HttpServletResponse response) {

	// 建立一個Cookie 物件
	Cookie cookie = new Cookie("username", "kaijun");

	// 設置過期時間,若無設置時間,其生命週期將持續到Session 過期為止
	cookie.setMaxAge(7*24*60*60);

	// 設置HTTPS 安全的Cookie
	cookie.setSecure(true);

	// 將Cookie 物件加入Response 中
	response.addCookie(cookie);
	
	return "add Cookie";
}

HttpOnly Cookie

HttpOnly Cooke 是用於防止跨站點腳本攻擊(XSS),也就是設置了HttpOnly 的Cookie 無法透過JavaScript 的Document.cookieAPI 訪問伺服器。

// 再改寫上面setCookie 方法
@RequestMapping(value = "/setCookie", method = RequestMethod.GET)
public String setCookie(HttpServletResponse response) {

	// 建立一個Cookie 物件
	Cookie cookie = new Cookie("username", "kaijun");

	// 設置過期時間,若無設置時間,其生命週期將持續到Session 過期為止
	cookie.setMaxAge(7*24*60*60);

	// 設置HTTPS 安全的Cookie
	cookie.setSecure(true);

	// 設置為不能被JS 訪問的Cookie
	cookie.setHttpOnly(true);

	// 將Cookie 物件加入Response 中
	response.addCookie(cookie);
	
	return "add Cookie";
}

刪除Cookie

到了最後不需要Cookie 值時,應該將其刪除以釋放記憶體資源,要刪除Cookie 需要將Cooke 值設為null 並將過期時間設置為0。

@RequestMapping(value = "/deleteCookie", method = RequestMethod.GET)
public String deleteCookie(HttpServletResponse response) {

	// 將Cookie 值設置為null
	Cookie cookie = new Cookie("username", null);

	// 設置過期時間為0
	cookie.setMaxAge(0);

	// 將Cookie 物件加入Response 中
	response.addCookie(cookie);
	
	return "delete Cookie";
}

參考網站

Cookie - 维基百科,自由的百科全书
如何在SpringBoot中使用Cookies


上一篇
Day 18 - Spring Boot 日誌紀錄
下一篇
Day 20 - Spring Boot & Session
系列文
誤打誤撞學了Spring Boot 還當了後端工程師30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言