目标

  1. 了解HTTP 请求/响应头及常见的属性;
  2. 了解如何使用SpringBoot处理头信息 ;
  3. 了解如何使用SpringBoot处理Cookie ;
  4. 学会如何对 Session 进行读写;
  5. 了解如何在不同请求间传递 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")
@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参数后,

通过该对象进行设置,上面的代码非常容易理解。

如果希望获得全部的请求头,可以使用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")
@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值,

且每访问一次则自增一次,这是一个简单的访问计数器功能。

如果希望获取全部的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机制存在一定的缺陷,尽可能在考虑一些风险后使用

  1. 安全性无法保证,除非使用HTTPS;
  2. 浏览器端只有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")
@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实现访问计数器的功能是一样的!

如果希望获取全部会话,可以使用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参数传递

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")
@ResponseBody
public 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的更多相关文章

  1. springboot中的几种scope

    写在开始 技术点 接受方式 判读在线方式 接受数据 发送数据 敬上代码 入口函数 消息处理 单聊实现 传送门: 回到顶部 写在开始 上面一篇写了一篇使用WebSocket做客户端,然后服务端是sock ...

  2. 补习系列(15)-springboot 分布式会话原理

    目录 一.背景 二.SpringBoot 分布式会话 三.样例程序 四.原理进阶 A. 序列化 B. 会话代理 C. 数据老化 小结 一.背景 在 补习系列(3)-springboot 几种scope ...

  3. 补习系列(14)-springboot redis 整合-数据读写

    目录 一.简介 二.SpringBoot Redis 读写 A. 引入 spring-data-redis B. 序列化 C. 读写样例 三.方法级缓存 四.连接池 小结 一.简介 在 补习系列(A3 ...

  4. 补习系列(7)-springboot 实现拦截的五种姿势

    目录 简介 姿势一.使用 Filter 接口 1. 注册 FilterRegistrationBean 2. @WebFilter 注解 姿势二.HanlderInterceptor 姿势三.@Exc ...

  5. 补习系列(19)-springboot JPA + PostGreSQL

    目录 SpringBoot 整合 PostGreSQL 一.PostGreSQL简介 二.关于 SpringDataJPA 三.整合 PostGreSQL A. 依赖包 B. 配置文件 C. 模型定义 ...

  6. 补习系列(18)-springboot H2 迷你数据库

    目录 关于 H2 一.H2 用作本地数据库 1. 引入依赖: 2. 配置文件 3. 样例数据 二.H2 用于单元测试 1. 依赖包 2. 测试配置 3. 测试代码 小结 关于 H2 H2 数据库是一个 ...

  7. 补习系列(16)-springboot mongodb 数据库应用技巧

    目录 一.关于 MongoDB 二.Spring-Data-Mongo 三.整合 MongoDB CRUD A. 引入框架 B. 数据库配置 C. 数据模型 D. 数据操作 E. 自定义操作 四.高级 ...

  8. 补习系列(17)-springboot mongodb 内嵌数据库

    目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...

  9. 补习系列(13)-springboot redis 与发布订阅

    目录 一.订阅发布 常见应用 二.Redis 与订阅发布 三.SpringBoot 与订阅发布 A. 消息模型 B. 序列化 C. 发布消息 D. 接收消息 小结 一.订阅发布 订阅发布是一种常见的设 ...

随机推荐

  1. Python操作Excel, 开发和调用接口,发送邮件

    笔记: 上周回顾: 模块: 导入模块的顺序 lyl.py # def hhh(): pass name = 'lyl' a.py import lyl import sys from lyl impo ...

  2. redis + cookies 实现持久登入

    通过登入把用户信息和token加载到redis中去, 将token和部分用户信息存储在cookie中, 下次登入时 判断cookie的token在redis中是否存在, 存在就把用户信息加载出来自动登 ...

  3. 基于用户协同过滤--UserCF

    UserCF  本系列文章主要介绍推荐系统领域相关算法原理及其实现.本文以项亮大神的<推荐系统实践>作为切入点,介绍推荐系统最基础的算法(可能也是最好用的)--基于用户的协同过滤算法(Us ...

  4. App间相互跳转及图片分享

    A-app: Info--URL Types--URL Schemes:A-app(一个标识,允许别的app调用本App) info.plist 添加白名单: LSApplicationQueries ...

  5. vuex学习

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 简单的理解就是你在state中定义了一个数 ...

  6. [Educational Round 10][Codeforces 652F. Ants on a Circle]

    题目连接:652F - Ants on a Circle 题目大意:\(n\)个蚂蚁在一个大小为\(m\)的圆上,每个蚂蚁有他的初始位置及初始面向,每个单位时间蚂蚁会朝着当前面向移动一个单位长度,在遇 ...

  7. B4 and After: Managing Hierarchy, Partitioning, and Asymmetry for Availability and Scale in Google’s Sofware-Defined WAN

    B4及之后:为谷歌软件定义WAN的可用性和扩展管理层次化.划分和不对称 本文为SIGCOMM 2018会议论文,由谷歌提供. 笔者翻译了该论文.由于时间仓促,且笔者英文能力有限,错误之处在所难免:欢迎 ...

  8. 企业IT管理员IE11升级指南【8】—— Win7 IE8和Win7 IE11对比

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  9. Java实现单例模式的9种方法

    一. 什么是单例模式 因程序需要,有时我们只需要某个类同时保留一个对象,不希望有更多对象,此时,我们则应考虑单例模式的设计. 二. 单例模式的特点 1. 单例模式只能有一个实例. 2. 单例类必须创建 ...

  10. http请求抓包神器-Fiddler(记录和检查你电脑的所有http通讯)

    Fiddler是做什么的,能帮助我们做什么? 1.能够监听http/httpS的流量,可以截获从浏览器或者客户端软件向服务器发送的http/https请求: 2.对截获之后的请求,我们还能够查看请求中 ...