为什么需要会话
为了成功完成登录功能,系统需要能够在每次请求时获取用户登录成功的标记。然而,HTTP协议
是无状态的协议,每一次HTTP请求都是独立的,服务器不会自动保存任何关于客户端的信息。因此,HTTP请求之间无法直接共享数据。为了解决这个问题并保持用户的状态信息(如是否已登录),我们需要引入会话技术
来实现多次请求之间的通信。
会话技术概览
在我们的日常生活中,会话是指谈话、交谈;但是在web开发
中,会话是指浏览器和服务器之间的一次连接(第一次连接),当浏览器第一次访问服务器时,会话就建立了。会话的“生命周期”十分长,直到任何一方断开连接,会话才会结束。在一次会话中,一般会包含多次请求和响应。
需要特别注意的是:会话是和浏览器关联的,当有多个浏览器和服务器建立连接
时,就有多个对话
。同一个浏览器在会话结束前,多次对服务器发起请求,多次请求都是属于同一个会话,如图所示,图中有三个浏览器
,都和服务器建立了连接
,所以说有三个会话
,但1、2、3
号请求都是属于同一个会话的
:
假如关闭了浏览器,则浏览器断开连接,该浏览器对应的对话就结束了,若关闭了web服务器
,则web服务器
上所有的会话都会立刻结束(这也说明了服务器稳定
的重要性)。
会话跟踪
会话跟踪技术是一种维护浏览器状态
的技术方法,服务器需要识别多次请求
是否来自同一个浏览器
,以便在同一次会话的多次请求之间共享数据
。(因为HTTP是无状态协议,需要数据共享)
服务器会接收到很多的请求,服务器需要识别到这些请求是否是同一个浏览器发出的。如图所示:
2、3请求
是同一个浏览器发出的,属于同一个会话;而3、5请求
不是同一个浏览器(同一种浏览器≠同一个浏览器)发出的,不属于同一个会话,而识别多次请求是否来自同一个浏览器的过程,就是会话跟踪
。
会话跟踪技术
Cookie
cookie
是客户端
会话跟踪技术,它是存储在客户端浏览器的,使用Cookie进行会话跟踪,需要在浏览器第一次发起请求(建立会话)
,请求服务器的时候,在服务端设置一个cookie
。
比如说客户端第一次请求了登录接口
,在登录功能执行完毕之后,就可以在服务端设置一个cookie
,在cookie
中我们可以保存一些用户登录相关的信息,比如用户名
、用户ID
等信息。
在服务端给客户端响应数据时,会自动将设置好、封装了数据的cookie
响应给浏览器,浏览器接收到响应的cookie
之后,也会自动将其保存在浏览器本地
;在后续的每一次请求中,由于请求是来自同一个浏览器,同一个会话,每一次请求都会将浏览器本地存储的cookie
自动携带到服务端。
接下来,服务端就可以获取到请求携带的cookie
值,然后判断其值上是否存在。如果存在该cookie
的值,那么说明当前用户的登录是成功的;反之,则说明当前用户登录失败。这样我们就可以基于cookie
在同一次会话的不同请求之间来共享数据。
因为cookie
是HTTP协议
中支持的技术,各大浏览器厂商都支持这一技术;而HTTP协议官方
提供了一个和cookie
相关的请求头
和响应头
:Set-Cookie响应头用于设置Cookie数据 (可以通过HttpServletResponse
这个类在服务端中设置cookie
) ;Cookie请求头用于每一次的请求携带Cookie数据 (同样可以使用HttpServletRequest
这个类在服务端获取cookie数据
)
操作Cookie
这是一个简单的设置和获取Cookie的后端实例代码:
/**
* 用于演示Cookie技术的Controller
*/
@Slf4j
@RestController
public class CookieController {
/**
* 设置Cookie
* @param response springboot自动封装的响应对象
* @return Result<Void>
*/
@GetMapping("/c1")
public Result<Void> setCookie(HttpServletResponse response) {
response.addCookie(new Cookie("login_username", "wzb"));
return Result.success();
}
/**
* 获取Cookie
* @param request springboot自动将请求数据封装的请求对象
* @return Result<Void>
*/
@GetMapping("/c2")
public Result<Void> getCookie(HttpServletRequest request) {
// 请求中可能会有很多Cookie,所以说是得到的Cookie数组
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equals("login_username")) {
log.info("login_user: {}", cookie.getValue());
}
}
return Result.success();
}
}
在服务端代码中,分别操作HttpServletResponse
实体对象设置cookie
,并给客户端响应;操作HttpServletRequest
实体对象获取请求携带的cookie数据
。对c1
请求路径发起请求:
我们可以看到在响应头Set-Cookie
中,服务端给客户端自动响应了一个login_user
的cookie
,这个cookie
正是服务端设置的,并且这个cookie
是自动存储在浏览器本地的:
然后再对c2
请求路径发起请求,我们可以看到请求头Cookie
中请求给服务端自动携带了login_user
这个cookie
:
服务端也成功获得了这个cookie
的值:
Cookie的优劣
Cookie
是HTTP协议
中支持的技术,cookie
从Set-Cookie响应头
中解析、保存到本地浏览器、发起请求自动在Cookie请求头
中携带cookie
,这些操作都是浏览器自动完成的,使用cookie
十分方便。
方便的同时,cookie
会话技术也有很多缺点,并且有些缺点在当今开发中是致命的! cookie
只能在电脑端使用,
移动端(Android&IOS)无法很好的使用cookie
因为cookie存储在本地浏览器,用户可以禁用、删除cookie,不安全, 当用户在本地浏览器禁用cookie
或者直接将其删除之后,再次请求服务端就会出现问题:
删除cookie或者禁用cookie
再次发起请求,发现报错
Cookie不能跨域使用
跨域需要从协议
、IP地址
、端口号
三个维度看,只要有任何一个维度不同,都属于跨域操作。
不支持跨域是cookie
最大的问题。在我们的学习阶段,虽然是前后端分离开发,但是请求的路径都是localhost(本机)
,相当于前后端都部署在同一个服务器,所以说cookie
是可以使用的。 但是现在的大部分项目,都是前后端分离开发的
,在部署的时候,前后端也会部署在不同的服务器中:
如图所示,我们打开浏览器直接访问前端,访问的url
是http://192.168.150.200:80/login.html
;然后在该页面向服务端发起登录请求,访问的url
是http://192.168.150.100:8080/login
,服务器设置了一个登录使用的cookie
响应给浏览器,此时就存在跨域操作了:我们是在http://192.168.150.200:80/login.html
这个页面上访问了http://192.168.150.100:8080/login
接口,此时服务器设置的cookie
是无法使用的。
总结
因为有这些局限,即使cookie
是HTTP协议
官方支持的技术;即使使用十分方便;但在现在的企业开发中,cookie
的身影已经减少很多了。还有一种会话技术叫Session
,这是底层基于Cookie
实现的存储在服务端的技术,且听下回分解。