Day 19 - Spring Boot & Cookie

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


<<:  CSS微动画 - 卡片简约动态效果,低调的小心机

>>:  day 26 - 如何知道我交出了一个有品质的系统

资料分类(Data classification)

资料分类是评估资料的业务价值或其重要性和对利益相关者的意义,以确定适当的保护级别的过程。可以从各种角...

Architecture

Architecture Components 以前 Android Developers 网站没有...

Day30 file system, inode

前言 时间终於过到了最後一天,昨天看了三个特别的虚拟文件系统,今天就看看实际存在的文件管理系统吧! ...

ISO 27001 资讯安全管理系统 【解析】(二十二)

识别威胁 在前面的概论中,我们知道威胁是外来的,他必须配合资产才会产生风险,所以资产与威胁是相互之...

【Day 08】List 介绍!

前言 list 是 Python 中最常见的资料类型,有许多的应用都会用到 list 喔! 今天会先...