spring boot補習系列之幾種scope詳解
目標
- 了解HTTP 請求/響應頭及常見的屬性;
- 了解如何使用SpringBoot處理頭信息 ;
- 了解如何使用SpringBoot處理Cookie ;
- 學會如何對 Session 進行讀寫;
- 了解如何在不同請求間傳遞 flash參數(shù)
一、Http 頭信息
HTTP 頭(Header)是一種附加內容,獨立于請求內容和響應內容。
HTTP 協(xié)議中的大量特性都通過Header信息交互來實現(xiàn),比如內容編解碼、緩存、連接?;畹鹊?。
如下面的一個請求響應:
Request
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Host: www.cnblogs.com
If-Modified-Since: Wed, 18 Jul 2018 13:47:45 GMT
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
| 名稱 | 用途 |
|---|---|
| Accept | 客戶端期望的MIME 類型列表 |
| Accept-Encoding | 客戶端期望的編解碼方式 |
| Accept-Language | 客戶端期望的語言 |
| Cache-Control | 緩存控制 |
| Connection | 連接行為(keep-alive) |
| Host | 請求訪問的主機 |
| If-Modified-Since | 緩存控制 |
| Upgrade-Insecure-Requests | 支持安全加密標記 |
| User-Agent | 用戶代理(客戶端標識) |
Response
Cache-Control: private, max-age=10
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 18 Jul 2018 13:47:51 GMT
Expires: Wed, 18 Jul 2018 13:48:01 GMT
Last-Modified: Wed, 18 Jul 2018 13:47:51 GMT
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
X-UA-Compatible: IE=10
| 名稱 | 用途 |
|---|---|
| Cache-Control | 緩存控制 |
| Connection | 連接行為(keep-alive) |
| Content-Encoding | 編解碼方式 |
| Content-Type | 內容類型(MIME) |
| Date | 當前響應時間 |
| Expires | 文檔過期時間 |
| Last-Modified | 最后一次更新時間 |
| Transfer-Encoding | 傳輸編碼方式 |
| Vary | 需要刷新的請求Header |
| X-Frame-Options | FRAME展示策略(用于同源控制) |
| X-UA-Compatible | IE兼容屬性 |
更多的** Http Header **可以從這里找到
二、SpringBoot 處理頭信息
前面的內容中已經講過如何完成Controller方法及請求的映射。
在SpringBoot可通過@RequestHeader注解方式
將請求頭信息映射到參數(shù),如下面的片段:
@GetMapping("/some")
@ResponseBody
public String someHeader(@RequestHeader(value = "Host") String host,
@RequestHeader(value = "User-Agent") String userAgent,
@RequestHeader(value = "Cache-Control", required = false) String cacheControl,
HttpServletResponse response) {
logger.info("host:{}", host);
logger.info("User-Agent:{}", userAgent);
logger.info("Cache-Control:{}", cacheControl);
// 設置響應頭
response.setHeader("Cache-Control", "no-cache,no-store,must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
return "OK";
}
而響應頭呢,可以通過聲明一個HttpServletResponse參數(shù)后,
通過該對象進行設置,上面的代碼非常容易理解。
如果希望獲得全部的請求頭,可以使用HttpHeaders對象:
@GetMapping("/all")
public ResponseEntity<Map<String, List<String>>> allHeaders(@RequestHeader HttpHeaders headers) {
Map<String, List<String>> valueMap = new HashMap<String, List<String>>();
for (String header : headers.keySet()) {
valueMap.put(header, headers.get(header));
logger.info("header[{}]={}", header, headers.get(header));
}
// 通過ResponseEntity設置響應頭
ResponseEntity<Map<String, List<String>>> entity = ResponseEntity.status(HttpStatus.OK)
.header("new header", UUID.randomUUID().toString()).body(valueMap);
return entity;
}
上面的一段代碼中,可以將所有請求頭信息全部打印出來。
此外還須注意到,返回響應使用了ResponseEntity對象,這是一個用于直接表示
響應信息頭、內容的對象,利用ResponseEntity可以很方便的設置響應頭信息。
三、Cookie處理
Cookie一開始服務器用于辨別用戶信息而記錄在瀏覽器上的信息。
到目前為止Cookie作為客戶端的存儲有了非常多的應用場景。
SpringBoot 提供了@CookieValue以支持參數(shù)方式注入,如下:
@GetMapping("/some")
@ResponseBody
public String someCookie(@CookieValue(value = "counter", defaultValue = "0") int counter,
HttpServletResponse response) {
logger.info("counter:{}", counter);
counter += 1;
String newValue = counter + "";
// 設置Cookie
response.addCookie(new Cookie("counter", newValue));
return newValue;
}
上述代碼中,訪問/some 可以獲得一個counter的cookie值,
且每訪問一次則自增一次,這是一個簡單的訪問計數(shù)器功能。
如果希望獲取全部的Cookie,可以參考以下代碼:
@GetMapping("/all")
public ResponseEntity<Map<String, String>>allCookies(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> valueMap = new HashMap<String, String>();
for (Cookie cookie : request.getCookies()) {
valueMap.put(cookie.getName(), cookie.getValue());
logger.info("cookie[{}]={}", cookie.getName(), cookie.getValue());
}
// 設置Cookie
response.addCookie(new Cookie("key", UUID.randomUUID().toString()));
return new ResponseEntity<Map<String, String>>(valueMap, HttpStatus.OK);
}
清理全部Cookie
@GetMapping("/clear")
public ResponseEntity<Map<String, String>> clearCookies(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> valueMap = new HashMap<String, String>();
for (Cookie cookie : request.getCookies()) {
valueMap.put(cookie.getName(), cookie.getValue());
logger.info("cookie[{}]={}", cookie.getName(), cookie.getValue());
// 清除
cookie.setMaxAge(0);
response.addCookie(cookie);
}
return new ResponseEntity<Map<String, String>>(valueMap, HttpStatus.OK);
}
Cookie機制存在一定的缺陷,盡可能在考慮一些風險后使用
安全性無法保證,除非使用HTTPS;
瀏覽器端只有4KB大小的存儲上限;
四、Session處理
Session 指的是會話,是建立于Cookie機制上的一種身份識別方式。
由于Cookie自身的安全性和容量限制,大多數(shù)應用中是在Cookie中存放一個唯一憑證;
服務側通過憑證再進行身份信息的存取,這就是會話的由來。
不同的語言、框架采用的實現(xiàn)方式有些差異,比如JavaEE采用JSESSION_ID,而PHP則是PHPSESSID
Session的交互原理可以參考下面一個圖:

Springboot 內嵌了Servlet容器,則是沿用的JSESSION_ID。因此在瀏覽一些JavaWeb站點時會發(fā)現(xiàn)該Cookie。
使用@SessionAttribute可以將會話中的屬性映射到方法參數(shù);
如果希望對Session屬性進行操作,可以在Controller上聲明@SessionAttributes注解以指定想要變更的屬性;
之后,通過Model參數(shù)進行寫入即可(由框架自動檢測并修改Session)
@SessionAttributes("seed")
public class SessionController {
private static final Logger logger = LoggerFactory.getLogger(SessionController.class);
@GetMapping("/some")
@ResponseBody
public String someSession(@SessionAttribute(value = "seed", required = false) Integer seed, Model model) {
logger.info("seed:{}", seed);
if (seed == null) {
seed = (int) (Math.random() * 10000);
} else {
seed += 1;
}
model.addAttribute("seed", seed);
return seed + "";
}
上面的例子與Cookie實現(xiàn)訪問計數(shù)器的功能是一樣的!
如果希望獲取全部會話,可以使用HttpSession
@GetMapping("/all")
public ResponseEntity<Map<String, Object>> allSessions(HttpSession session) {
Map<String, Object> valueMap = new HashMap<String, Object>();
Enumeration<String> iSession = session.getAttributeNames();
while (iSession.hasMoreElements()) {
String sessionName = iSession.nextElement();
Object sessionValue = session.getAttribute(sessionName);
valueMap.put(sessionName, sessionValue);
logger.info("sessoin[{}]={}", sessionName, sessionValue);
}
// 寫入session
session.setAttribute("timestmap", new Date());
return new ResponseEntity<Map<String, Object>>(valueMap, HttpStatus.OK);
}
清除會話
@GetMapping("/clear")
public ResponseEntity<Map<String, Object>> clearSessions(HttpSession session) {
Map<String, Object> valueMap = new HashMap<String, Object>();
Enumeration<String> iSession = session.getAttributeNames();
while (iSession.hasMoreElements()) {
String sessionName = iSession.nextElement();
Object sessionValue = session.getAttribute(sessionName);
valueMap.put(sessionName, sessionValue);
logger.info("sessoin[{}]={}", sessionName, sessionValue);
session.removeAttribute(sessionName);
}
return new ResponseEntity<Map<String, Object>>(valueMap, HttpStatus.OK);
}
五、Flash參數(shù)傳遞
Flash的意思是一瞬間,一閃而過的,因此很好理解,這是一類僅用來消費一次的參數(shù),有些類似閱后即焚。
試想這樣的場景,你確認完購物車,完成訂單支付后進入訂單管理界面,而此時界面上提示你"下單成功,請等待發(fā)貨"。
這便可以通過Flash傳參來實現(xiàn)。
Flash的意義是用作請求之間的瞬時參數(shù)傳遞,僅消費一次后便不再用。
以下是一個示例:
/**
* 執(zhí)行跳轉,并設置傳值
*
* @param counter
* @param response
* @return
*/
@GetMapping("/first")
public String first(final RedirectAttributes redirectAttrs) {
logger.info("redirect start:{}");
redirectAttrs.addFlashAttribute("flash", UUID.randomUUID().toString());
return "redirect:/flash/second";
}
/**
* 獲取傳值
*
* @param session
* @param response
* @return
*/
@GetMapping("/second")
@ResponseBody
public String second(@ModelAttribute("flash") String flash) {
logger.info("redirect receive {}", flash);
return flash;
}
交互原理

Sprintboot中Flash機制也是利用Session實現(xiàn)的,其中FlashMapManager接口實現(xiàn)了Flash參數(shù)的管理。
默認的實現(xiàn)是SessionFlashMapManager,可以通過RequestContextUtils獲得上下文中的FlashMapManager對象。
RequestContextUtils通過Request Scope(請求上下文)存取對象
這也是一個本文未提及的scope域,Request上下文是利用線程變量實現(xiàn)的,通常用于線程內業(yè)務處理的數(shù)據(jù)交互。
小結
HTTP 頭信息是一種附加內容,用于實現(xiàn)HTTP協(xié)議中的各種特性,在開始部分介紹了常見的頭信息定義。
本文主要介紹了幾種常見的HTTP scope信息的存取方法,包括如何對header、cookie進行讀取及修改。
springboot 內嵌了Servlet容器,會話處理機制上沿用了JSESSIONID,通過代碼示例介紹了會話的處理方法;
Flash參數(shù)是一種閱后即焚的數(shù)據(jù),其底層實現(xiàn)也用了session的實現(xiàn)方案。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
Spring Cloud Alibaba 本地調試介紹及方案設計
為了解決 本地調試 的問題,本文實現(xiàn)了一種簡單實用的策略,可以通過 Nacos 動態(tài)配置服務路由,還可以基于用戶,部門,組織等級別配置服務路由,實現(xiàn) 本地調試 的同時,實際上也實現(xiàn) 灰度發(fā)布,感興趣的朋友跟隨小編一起看看吧2021-07-07
java結合WebSphere MQ實現(xiàn)接收隊列文件功能
WebSphereMQ,也稱MQSeries,以一致的、可靠的和易于管理的方式來連接應用程序,并為跨部門、企業(yè)范圍的集成提供了可靠的基礎。通過為重要的消息和事務提供可靠的、一次且僅一次的傳遞,MQ可以處理復雜的通信協(xié)議,并動態(tài)地將消息傳遞工作負載分配給可用的資源。2015-10-10
詳解Intellij IDEA的Facets和Artifacts
這篇文章主要介紹了Intellij IDEA的Facets和Artifacts的相關知識,本文通過實例給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-09-09

