您好,登錄后才能下訂單哦!
目標(biāo)
一、Http 頭信息
HTTP 頭(Header)是一種附加內(nèi)容,獨(dú)立于請(qǐng)求內(nèi)容和響應(yīng)內(nèi)容。
HTTP 協(xié)議中的大量特性都通過Header信息交互來實(shí)現(xiàn),比如內(nèi)容編解碼、緩存、連接保活等等。
如下面的一個(gè)請(qǐng)求響應(yīng):
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 | 請(qǐng)求訪問的主機(jī) |
If-Modified-Since | 緩存控制 |
Upgrade-Insecure-Requests | 支持安全加密標(biāo)記 |
User-Agent | 用戶代理(客戶端標(biāo)識(shí)) |
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 | 內(nèi)容類型(MIME) |
Date | 當(dāng)前響應(yīng)時(shí)間 |
Expires | 文檔過期時(shí)間 |
Last-Modified | 最后一次更新時(shí)間 |
Transfer-Encoding | 傳輸編碼方式 |
Vary | 需要刷新的請(qǐng)求Header |
X-Frame-Options | FRAME展示策略(用于同源控制) |
X-UA-Compatible | IE兼容屬性 |
更多的** Http Header **可以從這里找到
二、SpringBoot 處理頭信息
前面的內(nèi)容中已經(jīng)講過如何完成Controller方法及請(qǐng)求的映射。
在SpringBoot可通過@RequestHeader注解方式
將請(qǐng)求頭信息映射到參數(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); // 設(shè)置響應(yīng)頭 response.setHeader("Cache-Control", "no-cache,no-store,must-revalidate"); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0); return "OK"; }
而響應(yīng)頭呢,可以通過聲明一個(gè)HttpServletResponse參數(shù)后,
通過該對(duì)象進(jìn)行設(shè)置,上面的代碼非常容易理解。
如果希望獲得全部的請(qǐng)求頭,可以使用HttpHeaders對(duì)象:
@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設(shè)置響應(yīng)頭 ResponseEntity<Map<String, List<String>>> entity = ResponseEntity.status(HttpStatus.OK) .header("new header", UUID.randomUUID().toString()).body(valueMap); return entity; }
上面的一段代碼中,可以將所有請(qǐng)求頭信息全部打印出來。
此外還須注意到,返回響應(yīng)使用了ResponseEntity對(duì)象,這是一個(gè)用于直接表示
響應(yīng)信息頭、內(nèi)容的對(duì)象,利用ResponseEntity可以很方便的設(shè)置響應(yīng)頭信息。
三、Cookie處理
Cookie一開始服務(wù)器用于辨別用戶信息而記錄在瀏覽器上的信息。
到目前為止Cookie作為客戶端的存儲(chǔ)有了非常多的應(yīng)用場(chǎng)景。
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 + ""; // 設(shè)置Cookie response.addCookie(new Cookie("counter", newValue)); return newValue; }
上述代碼中,訪問/some 可以獲得一個(gè)counter的cookie值,
且每訪問一次則自增一次,這是一個(gè)簡(jiǎn)單的訪問計(jì)數(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()); } // 設(shè)置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機(jī)制存在一定的缺陷,盡可能在考慮一些風(fēng)險(xiǎn)后使用
安全性無法保證,除非使用HTTPS;
瀏覽器端只有4KB大小的存儲(chǔ)上限;
四、Session處理
Session 指的是會(huì)話,是建立于Cookie機(jī)制上的一種身份識(shí)別方式。
由于Cookie自身的安全性和容量限制,大多數(shù)應(yīng)用中是在Cookie中存放一個(gè)唯一憑證;
服務(wù)側(cè)通過憑證再進(jìn)行身份信息的存取,這就是會(huì)話的由來。
不同的語言、框架采用的實(shí)現(xiàn)方式有些差異,比如JavaEE采用JSESSION_ID,而PHP則是PHPSESSID
Session的交互原理可以參考下面一個(gè)圖:
Springboot 內(nèi)嵌了Servlet容器,則是沿用的JSESSION_ID。因此在瀏覽一些JavaWeb站點(diǎn)時(shí)會(huì)發(fā)現(xiàn)該Cookie。
使用@SessionAttribute可以將會(huì)話中的屬性映射到方法參數(shù);
如果希望對(duì)Session屬性進(jìn)行操作,可以在Controller上聲明@SessionAttributes注解以指定想要變更的屬性;
之后,通過Model參數(shù)進(jìn)行寫入即可(由框架自動(dòng)檢測(cè)并修改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實(shí)現(xiàn)訪問計(jì)數(shù)器的功能是一樣的!
如果希望獲取全部會(huì)話,可以使用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); }
清除會(huì)話
@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的意思是一瞬間,一閃而過的,因此很好理解,這是一類僅用來消費(fèi)一次的參數(shù),有些類似閱后即焚。
試想這樣的場(chǎng)景,你確認(rèn)完購物車,完成訂單支付后進(jìn)入訂單管理界面,而此時(shí)界面上提示你"下單成功,請(qǐng)等待發(fā)貨"。
這便可以通過Flash傳參來實(shí)現(xiàn)。
Flash的意義是用作請(qǐng)求之間的瞬時(shí)參數(shù)傳遞,僅消費(fèi)一次后便不再用。
以下是一個(gè)示例:
/** * 執(zhí)行跳轉(zhuǎn),并設(shè)置傳值 * * @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機(jī)制也是利用Session實(shí)現(xiàn)的,其中FlashMapManager接口實(shí)現(xiàn)了Flash參數(shù)的管理。
默認(rèn)的實(shí)現(xiàn)是SessionFlashMapManager,可以通過RequestContextUtils獲得上下文中的FlashMapManager對(duì)象。
RequestContextUtils通過Request Scope(請(qǐng)求上下文)存取對(duì)象
這也是一個(gè)本文未提及的scope域,Request上下文是利用線程變量實(shí)現(xiàn)的,通常用于線程內(nèi)業(yè)務(wù)處理的數(shù)據(jù)交互。
小結(jié)
HTTP 頭信息是一種附加內(nèi)容,用于實(shí)現(xiàn)HTTP協(xié)議中的各種特性,在開始部分介紹了常見的頭信息定義。
本文主要介紹了幾種常見的HTTP scope信息的存取方法,包括如何對(duì)header、cookie進(jìn)行讀取及修改。
springboot 內(nèi)嵌了Servlet容器,會(huì)話處理機(jī)制上沿用了JSESSIONID,通過代碼示例介紹了會(huì)話的處理方法;
Flash參數(shù)是一種閱后即焚的數(shù)據(jù),其底層實(shí)現(xiàn)也用了session的實(shí)現(xiàn)方案。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。