前端面试题必考(四)- HTTP短连接,长连接(keep-alive),websocket,postmessage

本文深入探讨HTTP与TCP的关系,解析短连接与长连接的工作原理,详细介绍WebSocket的握手过程及PostMessage跨源通信机制,对比各协议特点及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.HTTP与TCP的关系

  • HTTP属于应用层协议,主要解决如何包装数据;
  • 在传输层使用TCP协议,主要解决数据如何在网络中传输;
  • 在网络层使用IP协议,主要解决网络路由和寻址问题;
  • HTTP把TCP分割好的各种数据包封装到IP包里面传送给接收方。

二.短连接、长连接、websocket、postmessage作用

1.短连接:(占用较多内存和带宽)

在HTTP/1.0中,默认使用的是短连接。浏览器和服务器每进行一次HTTP操作,就建立一次连接,但服务器向发送响应数据后,将关闭TCP,中断连接。WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源;并发量大,但每个用户无需频繁操作情况下,使用短连接更好。

2.长连接:(省时间,少带宽)。

但从 HTTP/1.1起,默认使用长连接。会在响应头有加入这行代码: Connection:keep-alive;TCP连接在发送后将仍然保持打开状态,浏览器可以继续通过相同的连接发送请求,即把多个HTTP请求合并为一个。也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。但是请记住 Request = Response, 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。

3.WebSocket:(无需循环等待(长轮询),CPU和内存资源不以客户端数量衡量,而是以客户端事件数衡量。)

WebSocket是HTML5出的协议,IE10以上浏览器支持,跟HTTP协议没有关系。只是借用了HTTP的协议来完成一部分握手。HTTP是不支持持久连接的(长连接,循环连接的不算),Websocket是一个持久化的协议;


4.PostMessage:可以安全地实现跨源通信IE8以上支持。主窗口通过postMessageAPI向异域的窗口发送数据,在异域的页面脚本中始终监听message事件,当获取主窗口数据时处理数据或者以同样的方式返回数据从而实现跨窗口的异域通讯。

 

三.Websocket握手过程(参考:https://www.cnblogs.com/oshyn/p/3574497.html

Websocket协议定义为ws和wss协议,分别为普通请求和基于SSL的安全传输,占用端口与http协议系统,ws为80端口,wss为443端口。

ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

其中port是可选项,query前接“?”。

1.当建立一个Websocket连接时,连接状态是CONNECTING,客户端通过HTTP请求与WebSocket服务端协商升级协议,需要提供host、port、resource-name和一个是否是安全连接的标记,也就是一个WebSocket URI,采用的是标准的HTTP报文格式,且只支持GET方法。

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

这个升级的HTTP请求头中的字段顺序是可以随便的。与普通HTTP请求相比多了一些字段。

  • Sec-WebSocket-Protocol:字段表示客户端可以接受的子协议类型,也就是在Websocket协议上的应用层协议类型。上面可以看到客户端支持chat和superchat两个应用层协议,当服务器接受到这个字段后要从中选出一个协议返回给客户端。
  • Upgrade:告诉服务器这个HTTP连接是升级的Websocket连接。
  • Connection:告知服务器当前请求连接是升级的。
  • Origin:该字段是用来防止客户端浏览器使用脚本进行未授权的跨源攻击,这个字段在WebSocket协议中非常重要。服务器要根据这个字段判断是否接受客户端的Socket连接。可以返回一个HTTP错误状态码来拒绝连接。
  • Sec-WebSocket-Key:为了表示服务器同意和客户端进行Socket连接,服务器端需要使用客户端发送的这个Key进行校验,然后返回一个校验过的字符串给客户端,客户端验证通过后才能正式建立Socket连接。服务器验证方法是:首先进行 Key + 全局唯一标示符(GUID)“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”连接起来,然后将连接起来的字符串使用SHA-1哈希加密,再进行base64加密,将得到的字符串返回给客户端作为握手依据。其中GUID是一个对于不识别WebSocket的网络端点不可能使用的字符串。

发送请求的要求(排查错误的方法/连接失败的原因):

  • 请求的WebSocket URI必须要是定义的有效的URI。
  • 如果客户端已经有一个WebSocket连接到远程服务器端,不论是否是同一个服务器,客户端必须要等待上一个连接关闭后才能发送新的连接请求,也就是同一客户端一次只能存在一个WebSocket连接。如果想同一个服务器有多个连接,客户端必须要串行化进行。如果客户端检测到多个到不同服务器的连接,应该限制一个最大连接数,在web浏览器中应该设定最多可以打开的标签页的数目。这样可以防止到远程服务器的DDOS攻击,但这是对到多个服务器的连接,如果是到同一个服务器连接,并没有数目限制。
  • 如果使用了代理服务器,那么客户端建立连接的时候需要告知代理服务器向目标服务器打开TCP连接。
  • 如果连接没有打开,一定是某一方出现错误,此时客户端必须要关闭再次连接的尝试。
  • 连接建立后,握手必须要是一个有效的HTTP请求
  • 请求的方式必须是GET,HTTP协议的版本至少是1.1
  • Upgrade字段必须包含而且必须是"websocket",Connection字段必须内容必须是“Upgrade”
  • Sec-Websocket-Version必须,而且必须是13

2.服务器返回响应头,客户端验证通过后将建立连接,此时状态为OPEN。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

Sec-WebSocket-Accept是根据客户端请求首部的Sec-WebSocket-Key计算出来的:

计算公式为:

  • Sec-WebSocket-Key258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接。
  • 通过SHA1计算出摘要,并转成base64字符串。

3.判断服务器返回的响应头是否同意握手的依据:

  • 首行返回的是HTTP/1.1协议版本和状态码101,表示变换协议(Switching Protocol)
  • Upgrade 和 Connection:这两个字段是服务器返回的告知客户端同意使用升级并使用websocket协议,用来完善HTTP升级响应
  • Sec-WebSocket-Accept:服务器端将加密处理后的握手Key通过这个字段返回给客户端表示服务器同意握手建立连接。
  • Sec-Websocket-Procotol:服务器选择的一个应用层协议。

浏览器解析响应头字段,如果Sec-WebSocket-Accept字段的信息符合要求就会建立连接,同时就可以发送WebSocket的数据帧了。如果该字段不符合要求或者为空或者HTTP状态码不为101,就不会建立连接。

服务器端响应步骤:

  • 解析握手请求头:获取握手依据Key并进行处理,检测HTTP的GET请求和版本是否准确,Host字段是否有权限,Upgrade字段中websocket是一个与大小写无关的ASCII字符串,Connection字段是一个大小写无关的"Upgrade"ASCII字符串,Websocket协议版本必须为13,其他的关于Origin、Protocol和Extensions可选。
  • 发送握手响应头:检测是否是wss协议连接,如果是就是用TLS握手连接,否则就是普通连接。服务器可以添加额外的验证信息到客户端进行验证。当进行一系列验证之后,服务器必须返回一个有效的HTTP响应头。响应头中每一行一个字段,结束必须为“\r\n”,使用的ABNF语法。

除了上述必要头字段之外,其他的HTTP协议定义的字段都可以使用,如Set-Cookie等。

同样类似AJAX的是,WebSocket对象也有一个readyState属性,用来表示对象实例当前所处的链接状态,有四个值:

  • 0:表示正在连接中(CONNECTING);
  • 1:表示连接成功,可以通信(OPEN);
  • 2:表示连接正在关闭(CLOSING);
  • 3:表示连接已经关闭或打开连接失败(CLOSED);

四.PostMessage(跨源通信)

以上这些跨域技术都只适用于客户端请求异域服务端资源的情景。而除此之外,有时候我们还需要在异域的两个客户端之间共享数据,例如页面与内嵌iframe窗口通讯,页面与新打开异域页面通讯。

任何域都可以通过postMessage发送跨域信息,因此只要有消息通过postMessage发送过来,脚本都会接收并进行处理。如何鉴别发送至页面的信息呢?答案是通过 message事件监听函数的事件对象,我们称它为event,该对象有三个属性:

  • data:值为其他window传递过来的对象;
  • origin:值为消息发送方窗口的域名;
  • source:值为对发送消息的窗口对象的引用;

很显然的,我们应该着重检测event对象的origin属性,建立一个白名单对origin属性进行检测通常是一个明智的做法。

 

 

-------------------------------<本节完>------------------------------------------

 

 

### 三级标题:Vue.js 数据可视化看板开发常见面试题及解答 #### 常见问题一:如何在 Vue 中实现数据可视化看板? 在 Vue 中实现数据可视化看板通常需要结合图表库,如 ECharts、Chart.js 或 D3.js。这些库提供了丰富的图表类型交互功能,能够满足大多数数据可视化需求。 - **ECharts** 是一个强大的开源可视化库,支持多种图表类型,并且可以轻松集成到 Vue 项目中。可以通过 `vue-echarts` 这样的封装组件来简化集成过程。 ```bash npm install echarts vue-echarts ``` 然后在组件中引入并使用: ```vue <template> <div> <line-chart :data="chartData" /> </div> </template> <script> import { LineChart } from 'vue-echarts'; export default { components: { LineChart, }, data() { return { chartData: { labels: ['January', 'February', 'March'], datasets: [ { label: 'Sales', data: [10, 20, 30], backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1, }, ], }, }; }, }; </script> ``` - **Chart.js** 是另一个轻量级的图表库,适合简单的数据可视化需求。它同样可以通过 Vue 插件进行集成。 ```bash npm install chart.js vue-chartjs ``` 然后在组件中使用: ```vue <template> <div> <bar-chart :data="chartData" /> </div> </template> <script> import { BarChart } from 'vue-chartjs'; export default { components: { BarChart, }, data() { return { chartData: { labels: ['January', 'February', 'March'], datasets: [ { label: 'Sales', data: [10, 20, 30], backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1, }, ], }, }; }, }; </script> ``` #### 常见问题二:如何优化 Vue 数据可视化看板的性能? 优化 Vue 数据可视化看板的性能可以从以下几个方面入手: 1. **减少不必要的重新渲染**:使用 Vue 的 `v-once` 指令或 `keep-alive` 组件来缓存静态内容,避免重复渲染。 ```vue <template> <div v-once> <!-- 静态内容 --> </div> </template> ``` 2. **懒加载图表组件**:对于不立即需要显示的图表,可以使用 Vue 的异步组件或动态导入来延迟加载。 ```javascript const LazyChart = () => import('@/components/Chart.vue'); ``` 3. **分页或虚拟滚动**:如果数据量非常大,可以考虑分页加载或使用虚拟滚动技术来减少 DOM 节点的数量。 ```vue <template> <virtual-scroller :items="largeDataset" :item-size="50"> <template #default="{ item }"> <div>{{ item.name }}</div> </template> </virtual-scroller> </template> ``` 4. **优化图表配置**:对于复杂的图表,适当调整图表的配置项,例如减少动画效果、降低分辨率等。 ```javascript options: { animation: false, responsive: true, maintainAspectRatio: false, } ``` 5. **使用 Web Workers**:对于计算密集型的任务,可以将部分逻辑移到 Web Worker 中执行,避免阻塞主线程。 ```javascript const worker = new Worker('worker.js'); worker.postMessage(data); worker.onmessage = function(event) { // 处理结果 }; ``` #### 常见问题三:如何处理 Vue 数据可视化看板中的大量数据? 处理 Vue 数据可视化看板中的大量数据时,需要注意以下几点: 1. **数据聚合与抽样**:对于超大数据集,可以先对数据进行聚合或抽样处理,减少实际渲染的数据量。 ```javascript function aggregateData(data, interval) { const aggregated = []; for (let i = 0; i < data.length; i += interval) { const chunk = data.slice(i, i + interval); const sum = chunk.reduce((acc, val) => acc + val.value, 0); aggregated.push({ timestamp: chunk[0].timestamp, value: sum }); } return aggregated; } ``` 2. **分页加载**:将数据分成多个页面,每次只加载当前页面的数据,减少一次性加载的压力。 ```vue <template> <div> <button @click="loadPage(currentPage - 1)">Previous</button> <button @click="loadPage(currentPage + 1)">Next</button> <div v-for="item in currentPageData" :key="item.id">{{ item.name }}</div> </div> </template> ``` 3. **使用虚拟滚动**:通过虚拟滚动技术,只渲染可视区域内的数据项,大大减少 DOM 节点的数量。 ```vue <template> <virtual-scroller :items="largeDataset" :item-size="50"> <template #default="{ item }"> <div>{{ item.name }}</div> </template> </virtual-scroller> </template> ``` 4. **WebGL 加速**:对于大规模图形渲染,可以考虑使用 WebGL 技术,利用 GPU 加速提升性能。 ```javascript import * as THREE from 'three'; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); ``` 5. **数据流优化**:使用 Vuex 或其他状态管理工具,确保数据流清晰且高效,避免不必要的数据更新。 ```javascript const store = new Vuex.Store({ state: { largeDataset: [], }, mutations: { updateDataset(state, newData) { state.largeDataset = newData; }, }, actions: { fetchDataset({ commit }) { // 异步获取数据 commit('updateDataset', processedData); }, }, }); ``` #### 常见问题:如何在 Vue 中实现动态更新图表数据? 在 Vue 中实现动态更新图表数据通常涉及以下几个步骤: 1. **绑定数据源**:将图表的数据源与 Vue 的响应式数据绑定在一起。 ```vue <template> <div> <line-chart :data="chartData" /> </div> </template> <script> import { LineChart } from 'vue-echarts'; export default { components: { LineChart, }, data() { return { chartData: { labels: ['January', 'February', 'March'], datasets: [ { label: 'Sales', data: [10, 20, 30], backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1, }, ], }, }; }, }; </script> ``` 2. **监听数据变化**:使用 Vue 的 `watch` 监听器来检测数据变化,并触发图表更新。 ```javascript watch: { chartData: { handler(newVal) { this.$refs.chart.update(); }, deep: true, }, }, ``` 3. **手动更新图表**:在某些情况下,可能需要手动调用图表实例的方法来更新图表。 ```javascript methods: { updateChart() { this.$refs.chart.update(); }, }, ``` 4. **定时刷新**:如果数据需要定期更新,可以使用 `setInterval` 来定时获取新数据并更新图表。 ```javascript mounted() { setInterval(() => { // 获取新数据 this.fetchNewData(); }, 5000); }, ``` 5. **WebSocket 实时更新**:对于实时性要求较高的场景,可以使用 WebSocket 来实现实时数据推送更新。 ```javascript mounted() { const socket = new WebSocket('wss://example.com/socket'); socket.addEventListener('message', (event) => { const newData = JSON.parse(event.data); this.updateChartData(newData); }); }, ``` #### 常见问题五:如何在 Vue 中实现多维度数据筛选过滤? 在 Vue 中实现多维度数据筛选过滤通常涉及以下几个步骤: 1. **定义筛选条件**:创建多个筛选条件输入框,允许用户选择不同的筛选维度。 ```vue <template> <div> <select v-model="selectedCategory"> <option v-for="category in categories" :key="category">{{ category }}</option> </select> <input type="number" v-model.number="minValue" placeholder="Min Value" /> <input type="number" v-model.number="maxValue" placeholder="Max Value" /> </div> </template> ``` 2. **处理筛选逻辑**:编写方法来处理用户的筛选请求,并根据条件过滤数据。 ```javascript methods: { filterData() { let filtered = this.rawData; if (this.selectedCategory !== '') { filtered = filtered.filter(item => item.category === this.selectedCategory); } if (this.minValue !== null && this.minValue !== '') { filtered = filtered.filter(item => item.value >= this.minValue); } if (this.maxValue !== null && this.maxValue !== '') { filtered = filtered.filter(item => item.value <= this.maxValue); } this.filteredData = filtered; }, }, ``` 3. **绑定筛选结果**:将筛选后的数据绑定到图表或其他展示组件上。 ```vue <template> <div> <line-chart :data="filteredData" /> </div> </template> ``` 4. **优化筛选性能**:对于大数据集,可以使用虚拟滚动或分页技术来提高筛选性能。 ```vue <template> <div> <virtual-scroller :items="filteredData" :item-size="50"> <template #default="{ item }"> <div>{{ item.name }}</div> </template> </virtual-scroller> </div> </template> ``` 5. **提供默认筛选条件**:为用户提供默认的筛选条件,帮助他们快速找到感兴趣的数据。 ```javascript data() { return { selectedCategory: 'All', minValue: '', maxValue: '', }; }, ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值