补习系列(3)-springboot中的几种scope
目标
- 了解HTTP 请求/响应头及常见的属性;
- 了解如何使用SpringBoot处理头信息 ;
- 了解如何使用SpringBoot处理Cookie ;
- 学会如何对 Session 进行读写;
- 了解如何在不同请求间传递 flash参数
一、Http 头信息
HTTP 头(Header)是一种附加内容,独立于请求内容和响应内容。
HTTP 协议中的大量特性都通过Header信息交互来实现,比如内容编解码、缓存、连接保活等等。
如下面的一个请求响应:
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注解方式
将请求头信息映射到参数,如下面的片段:
@GetMapping("/some")@ResponseBodypublic 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参数后,
通过该对象进行设置,上面的代码非常容易理解。
如果希望获得全部的请求头,可以使用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以支持参数方式注入,如下:
@GetMapping("/some")@ResponseBodypublic String someCookie(@CookieValue(value = "counter", defaultValue = "0") int counter,HttpServletResponse response) {logger.info("counter:{}", counter);counter += 1;String newValue = counter + "";// 设置Cookieresponse.addCookie(new Cookie("counter", newValue));return newValue;}
上述代码中,访问/some 可以获得一个counter的cookie值,
且每访问一次则自增一次,这是一个简单的访问计数器功能。
如果希望获取全部的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());}// 设置Cookieresponse.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自身的安全性和容量限制,大多数应用中是在Cookie中存放一个唯一凭证;
服务侧通过凭证再进行身份信息的存取,这就是会话的由来。
不同的语言、框架采用的实现方式有些差异,比如JavaEE采用JSESSION_ID,而PHP则是PHPSESSID
Session的交互原理可以参考下面一个图:
Springboot 内嵌了Servlet容器,则是沿用的JSESSION_ID。因此在浏览一些JavaWeb站点时会发现该Cookie。
使用@SessionAttribute可以将会话中的属性映射到方法参数;
如果希望对Session属性进行操作,可以在Controller上声明@SessionAttributes注解以指定想要变更的属性;
之后,通过Model参数进行写入即可(由框架自动检测并修改Session)
@SessionAttributes("seed")
public class SessionController {private static final Logger logger = LoggerFactory.getLogger(SessionController.class);@GetMapping("/some")@ResponseBodypublic 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实现访问计数器的功能是一样的!
如果希望获取全部会话,可以使用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);}// 写入sessionsession.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参数传递
Flash的意思是一瞬间,一闪而过的,因此很好理解,这是一类仅用来消费一次的参数,有些类似阅后即焚。
试想这样的场景,你确认完购物车,完成订单支付后进入订单管理界面,而此时界面上提示你"下单成功,请等待发货"。
这便可以通过Flash传参来实现。
Flash的意义是用作请求之间的瞬时参数传递,仅消费一次后便不再用。
以下是一个示例:
/*** 执行跳转,并设置传值** @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")@ResponseBodypublic String second(@ModelAttribute("flash") String flash) {logger.info("redirect receive {}", flash);return flash;}
交互原理
Sprintboot中Flash机制也是利用Session实现的,其中FlashMapManager接口实现了Flash参数的管理。
默认的实现是SessionFlashMapManager,可以通过RequestContextUtils获得上下文中的FlashMapManager对象。
RequestContextUtils通过Request Scope(请求上下文)存取对象
这也是一个本文未提及的scope域,Request上下文是利用线程变量实现的,通常用于线程内业务处理的数据交互。
码云同步代码
小结
HTTP 头信息是一种附加内容,用于实现HTTP协议中的各种特性,在开始部分介绍了常见的头信息定义。
本文主要介绍了几种常见的HTTP scope信息的存取方法,包括如何对header、cookie进行读取及修改。
springboot 内嵌了Servlet容器,会话处理机制上沿用了JSESSIONID,通过代码示例介绍了会话的处理方法;
Flash参数是一种阅后即焚的数据,其底层实现也用了session的实现方案。
欢迎继续关注"美码师的补习系列-springboot篇" ,期待更多精彩内容^-^
作者:美码师
补习系列(3)-springboot中的几种scope相关推荐
- 补习系列(3)-springboot 中的几种scope
目标 了解HTTP 请求/响应头及常见的属性: 了解如何使用SpringBoot处理头信息 : 了解如何使用SpringBoot处理Cookie : 学会如何对 Session 进行读写: 了解如何在 ...
- 补习系列(15)-springboot 分布式会话原理
目录 一.背景 二.SpringBoot 分布式会话 三.样例程序 四.原理进阶 A. 序列化 B. 会话代理 C. 数据老化 小结 一.背景 在 补习系列(3)-springboot 几种scope ...
- 补习系列(14)-springboot redis 整合-数据读写
目录 一.简介 二.SpringBoot Redis 读写 A. 引入 spring-data-redis B. 序列化 C. 读写样例 三.方法级缓存 四.连接池 小结 一.简介 在 补习系列(A3 ...
- 补习系列(7)-springboot 实现拦截的五种姿势
目录 简介 姿势一.使用 Filter 接口 1. 注册 FilterRegistrationBean 2. @WebFilter 注解 姿势二.HanlderInterceptor 姿势三.@Exc ...
- 补习系列(19)-springboot JPA + PostGreSQL
目录 SpringBoot 整合 PostGreSQL 一.PostGreSQL简介 二.关于 SpringDataJPA 三.整合 PostGreSQL A. 依赖包 B. 配置文件 C. 模型定义 ...
- 补习系列(18)-springboot H2 迷你数据库
目录 关于 H2 一.H2 用作本地数据库 1. 引入依赖: 2. 配置文件 3. 样例数据 二.H2 用于单元测试 1. 依赖包 2. 测试配置 3. 测试代码 小结 关于 H2 H2 数据库是一个 ...
- 补习系列(17)-springboot mongodb 内嵌数据库
目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...
- 补习系列(16)-springboot mongodb 数据库应用技巧
目录 一.关于 MongoDB 二.Spring-Data-Mongo 三.整合 MongoDB CRUD A. 引入框架 B. 数据库配置 C. 数据模型 D. 数据操作 E. 自定义操作 四.高级 ...
- 补习系列(13)-springboot redis 与发布订阅
目录 一.订阅发布 常见应用 二.Redis 与订阅发布 三.SpringBoot 与订阅发布 A. 消息模型 B. 序列化 C. 发布消息 D. 接收消息 小结 一.订阅发布 订阅发布是一种常见的设 ...
最新文章
- Object C语法学习
- 【原创】RabbitMQ 之 Access Control(翻译)
- [导入]sqlserver2005 数据挖掘控件研究
- A Class For Executing MSSql Store Procedure
- PID参数整定法(2)
- poj3278 CatchThatCow bfs
- centos python_【建议收藏】Python虚拟环境最全教程,看这篇就够了!
- python的网页解析器_网页解析器(BeautifulSoup)-- Python
- c语言 __FILE__,__DATE__,__TIME__ (宏)
- chrome vue 未响应_vue之骨架屏踩坑之路
- 基于高光谱遥感技术的农作物病虫害应用研究现状
- [linux-内核]内核日志及printk结构浅析
- dnf助手服务器内部出错,地下城与勇士TGP的DNF助手异常解决办法 TGP-DNF助手补丁不适配怎么办...
- 线性代数_1、二阶、三阶行列式、排列、逆序
- windows server 2016添加开机启动项
- C# 简单判断枚举值是否被定义
- *p++、*(p++)、(*p)++、*++p、++*p的区别
- Java开发环境基础配置
- MySQL-06-MD5加密
- Tarena代码-一些代码碎片
热门文章
- 代码编辑框控件_某游戏控件遍历
- linux系统怎么清理指定日期的文件,Linux系统删除指定时间段文件的方法(2)
- Windows 平台下基于MinGW和Qt 的OpenCV 之CMake 项目配置
- spring boot 相关注解
- NOIP2017金秋冲刺训练营杯联赛模拟大奖赛第二轮Day2题解
- 跨域问题解决(我只是搬运工)
- 洛谷 P4300 BZOJ 1266 [AHOI2006]上学路线route
- 51nod 1686 第K大区间 二分瞎搞
- Android基础学习第二篇—Activity
- Android 支付宝 移动支付接口 快速配置