笔者之前与一位同事研究了 Cypress 的 visit 方法,其源码实现最终是调用了 WebSocket 向 visit 参数里指定的 website 通行并获取数据,见下图变量 ev.data 的值。
我这位同事的研究成果,通过 Joplin 笔记记录如下如下。
于是笔者心里有一个疑问,为什么 Cypress 的 visit 方法选择了 WebSocket 作为与目标网站的通信技术呢?为什么不直接走 HTTP 协议,比如用 ES6 原生支持的 fetch 去访问目标网站呢?
要回答这个问题,我们先要理解到底什么是 WebSocket,以及它与 HTTP 相比较的优缺点。
诚然,WebSocket 可以在用户的浏览器和服务器之间打开交互式通信会话,浏览器可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。
WebSocket 基于 TCP 连接,在服务器和浏览器间提供了全双工通信功能,即服务器可以主动推送数据到浏览器端,而这在 HTTP 协议中是不可能实现的,HTTP 协议只支持浏览器到服务器端的 Request - Response 方式,即浏览器客户端如果想查询服务器端是否有最新的事件发生,则只能采取低效的轮询方式进行。
举个例子,当用户向服务器发送请求时,该请求以 HTTP 或 HTTPS 的形式发送,服务器收到请求后向客户端发送响应,每个请求都与相应的响应相关联,发送响应后连接关闭,每个 HTTP 或 HTTPS 请求每次都会建立与服务器的新连接,并且在获得响应后,连接会自行终止。
笔者注:HTTP 请求头部的 Connection: keep-alive 字段,可以实现连接重用的需求吗?
当启用 Keep-Alive 时,客户端和服务器同意为后续请求或响应保持连接打开。
默认情况下,HTTP 连接在数据事务结束时关闭。 这意味着客户端创建一个新连接来请求页面的每个文件,服务器在发送数据后关闭这些 TCP 连接。
但是,如果服务器需要同时响应多个 HTTP 请求并为每个新的 TCP 连接提供一个文件,则站点页面的加载时间将会增加。 这可能会导致糟糕的用户体验。
为了克服这个问题,网站所有者需要启用 Keep-Alive 标头来限制新连接的数量。
通过打开 Keep-Alive 连接标头,客户端可以通过单个 TCP 连接下载所有内容,例如 JavaScript、CSS、图像和视频,而不是为每个文件发送不同的请求。
这是一张演示 Keep-Alive 工作原理的图片: