1 前言
1.1 内容提要
- 理解使用会话技术的原因
- 理解客户端技术和服务器技术之间的区别
- 掌握Cookie的设置(构造),熟悉Cookie的获取,能够通过浏览器查看Cookie信息
- 理解Session维护的机制,能够分析Session的失效原因
- 熟悉使用Session存储和获取信息
- 掌握Cookie和Session的使用场景
1.2 前置知识准备
- 响应头的设置
- Postman中设置请求头
- URL编码(浏览器地址栏不能写中文或一些特殊的字符)
2 会话技术Conversation
同一个客户端向服务器中发送的多个请求,需要信息共享
在做服务器开发过程中,我们的客户端和服务器之间,会有请求报文和响应报文
客户端给服务器发送请求:请求报文
服务器给客户端发送响应:响应报文
HTTP协议的无状态性,会导致一个问题,服务器不清楚究竟是哪一个客户端
通过这种方式,携带了一些信息,服务器确实是可以知道 请求来自于哪一个客户端
通过上面这种方式,是否有弊端?
- 用户信息不安全
- 客户端和浏览器每一次发送请求的时候都需要携带请求参数比较繁琐
以会话的形式来体现客户端和服务器之间的交流,最重要的一件事情是要让服务器知道客户端是谁。
李雷(客户端):韩梅梅你好,我想请你吃饭
韩梅梅(服务器):(韩梅梅不知道你是谁)你是谁呀?
李雷(客户端):韩梅梅你好,我是李雷,我想请你吃饭
韩梅梅(服务器):可以啊,在哪里吃饭呢
李雷(客户端):我们去吃香他她煲仔饭吧
韩梅梅(服务器):你是谁,我是和谁去吃煲仔饭
李雷(客户端):吃完饭去看电影吧
韩梅梅(服务器):你是谁,我是和谁去看电影
如果没有会话技术,服务器不清楚每一次请求来源于哪一个客户端
如果引入会话技术,这段会话就会变成这个样子
李雷(客户端):韩梅梅你好,我是李雷,我想请你吃饭
韩梅梅(服务器):好啊,那吃什么
李雷(客户端):我们去吃香他她香他她煲仔饭吧
韩梅梅(服务器):好啊,那说好了,李雷咱两去吃煲仔饭,几点见面
李雷(客户端):晚上6点可以吗
韩梅梅(服务器):可以啊,那吃完饭呢
李雷(客户端):吃完饭去看电影吧
韩梅梅(服务器):好吧
如果做到的这件事情呢?
一种情况是,我直接告知你我的信息
李雷(客户端):韩梅梅你好,我是李雷,我想请你吃饭
韩梅梅(服务器):好啊,那吃什么 (我给你提醒,你要告诉我你是李雷)
李雷(客户端):我们去吃香他她香他她煲仔饭吧 (我是李雷)
韩梅梅(服务器):好啊,那说好了,李雷咱两去吃煲仔饭,几点见面
李雷(客户端):晚上6点可以吗(我是李雷)
韩梅梅(服务器):可以啊,那吃完饭呢
李雷(客户端):吃完饭去看电影吧(我是李雷)
韩梅梅(服务器):好吧
还有种情况,类似于你服务器端有个保险柜,告知我你的保险柜的编号,就可以获得保险柜,然后从保险柜中获得信息
李雷(客户端):韩梅梅你好,我是李雷,我想请你吃饭
韩梅梅(服务器):好啊,那吃什么 (我给你一个编号,这个编号是89757)
李雷(客户端):我们去吃香他她香他她煲仔饭吧 (编号89757)
韩梅梅(服务器):好啊,那说好了,李雷咱两去吃煲仔饭,几点见面
李雷(客户端):晚上6点可以吗(编号89757)
韩梅梅(服务器):可以啊,那吃完饭呢
李雷(客户端):吃完饭去看电影吧(编号89757)
韩梅梅(服务器):好吧
如果是客户端直接携带确切的信息,这个就是客户端技术;如果是通过客户端提供的编号,进而在服务器中进一步获得信息,那么这个就是服务器技术
服务器会话技术,是在客户端会话技术基础上的
归根结底:(身份)信息,究竟是客户端维护的,还是服务器维护的
客户端技术:Cookie
服务器技术:Session
3 客户端技术Cookie
携带信息:客户端(浏览器)在向服务器发起请求的时候直接携带了信息,这些信息是通过请求头中一个特殊的请求头携带的
这个特殊的请求头叫Cookie
3.1 Cookie的格式
Cookie:key1=value1;key2=value2
携带的是键值对信息,携带的键值对信息都是字符串信息
可以携带多组键值对信息,如果携带多组,中间使用分号分隔开
GET http://localhost:8080/ HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="116", "Not)A;Brand";v="24", "Microsoft Edge";v="116"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.62
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: name=lilei; age=18; gender=male; height=180
3.2 构造Cookie信息
这个过程是指,客户端(浏览器)在发起这个请求的时候,通过请求报文封装信息,请求报文中的请求头Cookie包含了对应的值
那么这里我们要构造Cookie信息,想办法让请求头Cookie里面包含对应的值
- 浏览器构造Cookie
- Postman构造Cookie
- 服务器构造Cookie
3.2.1 浏览器构造Cookie
步骤
- 打开开发者工具,快捷键F12
- 找应用程序(Application)
- 应用程序里找 存储(Storage)里的Cookie
请求报文:
GET http://localhost:8080/demo1/cookie/fetch HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="110", "Not A(Brand";v="24", "Microsoft Edge";v="110"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.46
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: zhangsan=123456; lisi=654321
第17行里的值
Cookie: zhangsan=123456; lisi=654321
3.2.2 Postman构造Cookie
也是构造Cookie这个请求头
请求报文
GET http://localhost:8080/demo1/cookie/fetch HTTP/1.1
Cookie: zhaoliu=123456;wangwu=789987
User-Agent: PostmanRuntime/7.29.2
Accept: */*
Host: localhost:8080
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
第2行
Cookie: zhaoliu=123456;wangwu=789987
3.2.3 服务器构造Cookie
客户端 → 服务器,请求
服务器 → 客户端,响应
客户端 → 服务器,请求
服务器能给客户端做的是响应
而我们希望的是客户端请求的时候携带Cookie
服务器提供特殊的响应报文,客户端获得这个特殊的请求报文之后,就会设置Cookie,在发送请求的时候就会携带Cookie了
特殊的响应报文,使用的是特殊的响应头,这个特殊的响应头set-cookie
/**
* 发送请求
* http://localhost:8080/demo1/cookie/set?username=lilei
* @author stone
* @date 2023/02/17 16:13
*/
@WebServlet("/cookie/set")
public class CookieSetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
// 把这个通过响应报文给到浏览器,并且让浏览器发起请求的时候,通过Cookie来携带
resp.setHeader("set-cookie","username=" + username);
}
}
来看一下这个请求的响应报文
HTTP/1.1 200
set-cookie: username=lilei
Content-Length: 0
Date: Fri, 17 Feb 2023 08:15:48 GMT
Keep-Alive: timeout=20
Connection: keep-alive
Response是针对于Cookie有提供特定的方法,能够让我们直接设置Cookie
resp.addCookie(new Cookie(“username”,username));
3.3 获取Cookie
要获得的是Cookie这个请求头
String result = request.getHeader(“Cookie”);
去解析里面的键值对
实际上我们并没有这样做,Request中提供了直接获得Cookie的方法
Cookie[] cookies = request.getCookies();
单个Cookie,我们先获得其键值对信息
键:cookie.getName()
值:cookie.getValue()
@WebServlet("/cookie/fetch")
public class CookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
String name = cookie.get