资讯详情

WebSocket面试深度拆解:握手、心跳、重连与粘包实战

📅 2026/10/22 15:25:19 | 华诺云谱 👁 阅读
WebSocket面试深度拆解:握手、心跳、重连与粘包实战
1. 面试官问WebSocket到底在问什么面到WebSocket这个题很多人第一反应是我知道全双工通信比轮询强。然后面试官追问一句那你说说它怎么保持连接不断场面就冷下来了。我面过不少人也被人面过发现一个规律WebSocket的面试题表面问协议实际考的是你对长连接这件事有没有真正的工程体感。你如果只背过八股文答出来的东西是飘的但凡自己动手搭过一个带心跳重连的实时模块哪怕只是个小聊天室回答的颗粒度完全不一样。这篇东西写给两类人一类是正在准备面试、想把WebSocket这块答扎实的开发者另一类是工作中要落地实时功能、但被断线重连、消息乱序这些问题折磨过的工程师。我会把面试里高频出现的几个问题拆开每个问题不光给答案还要讲清楚面试官问这个问题的真实意图是什么以及你该怎么答才能显得是真做过而不是背过。核心关键词就几个WebSocket握手、心跳保活、断线重连、粘包拆包、与轮询的取舍。这些词你面试大概率都会碰到。先说一个反直觉的结论面试官其实不太在乎你能不能背出WebSocket的握手报文长什么样他更在乎你知不知道WebSocket在什么场景下不该用。一个张口就说实时就用WebSocket的人和一个能说出消息频率低、服务端主动推送需求弱的时候SSE甚至短轮询更省事的人段位差得很明显。下面我按面试的真实节奏一层层往下拆。2. 握手阶段从HTTP升级到WebSocket面试官想听的不是背报文2.1 为什么WebSocket要借HTTP来完成握手这是面试里第一个高频问题也是最容易答得浮于表面的一个。很多人会说因为要兼容现有的HTTP基础设施这个答案对但不够。你得往下再挖一层WebSocket设计成用HTTP升级本质是为了复用80和443端口穿过那些只认HTTP的中间层。你想想如果WebSocket自己搞一个全新的协议、全新的端口那企业防火墙、反向代理、负载均衡这些中间设备全都要改配置才能放行。而借道HTTP的Upgrade机制握手阶段看起来就是一个普通的HTTP请求中间设备天然放行握手完成后才切换协议。这个设计决策背后是部署成本的考量不是技术上的必须。面试时你可以这样组织语言握手请求里带Connection: Upgrade和Upgrade: websocket两个头外加一个Sec-WebSocket-Key服务端把这个Key拼上一个固定的GUID做SHA-1哈希再Base64回给客户端Sec-WebSocket-Accept。这个校验过程不是为了加密是为了防止缓存代理把一次握手响应错误地复用给另一个连接。这一点如果你能主动说出来面试官基本会认为你读过协议细节。2.2 Sec-WebSocket-Key那串东西到底防的是什么我见过不少人以为这个Key是某种鉴权或者加密用的其实不是。它是一个随机生成的16字节Base64字符串服务端拿它加上固定字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11做哈希纯粹是为了证明我确实读懂了WebSocket协议不是随便一个HTTP服务器在瞎回。为什么需要这个证明因为中间可能存在缓存代理或者透明代理它们看到HTTP响应可能会缓存下来。如果服务端只是简单回一个200代理可能把这次响应缓存导致后续别的客户端握手时拿到错误的响应。加上这个Key校验每次握手的Key都不同响应也就不同缓存复用自然失效。这个点面试里能讲清楚的人不多属于加分项。2.3 握手阶段的常见追问与应答思路面试官常追问的几个点我列个表把他真正想听的和背八股会答的对比一下追问背八股的答法面试官真正想听的握手用的是什么HTTP方法GETGET且必须是HTTP/1.1及以上因为Upgrade是1.1才有的机制握手能带Cookie吗能能且这是WebSocket鉴权最常用的方式因为浏览器原生WebSocket API不支持自定义Header握手失败会怎样报错会退化成普通HTTP响应客户端收到非101状态码就认为握手失败此时连接不会升级能不能跨域能服务端不校验Origin就没有同源限制所以生产环境必须自己校验Origin防跨站连接最后那条特别值得展开。浏览器发起的WebSocket握手会带上Origin头但服务端默认不检查它。这意味着任何网页都能连你的WebSocket服务如果你的鉴权只靠Cookie那就存在被跨站利用的风险。面试里主动提这一点说明你有安全意识不是只会写Demo。3. 心跳与保活连接为什么会悄悄死掉3.1 TCP连接不是断了就一定会告诉你这是WebSocket面试里最能区分水平的一个问题。很多人以为连接断了客户端会收到close事件现实是大量连接是在双方都不知情的情况下变成僵尸连接的。原因在于TCP连接的断开需要一方主动发FIN包。如果中间的网络设备比如NAT网关、负载均衡因为空闲超时把连接表项清了它不会通知两端只是默默丢弃后续的包。这时候客户端以为连接还在服务端也以为连接还在但实际数据已经发不出去了。移动网络下这个问题尤其严重手机从WiFi切到4GIP变了旧连接直接失效但应用层可能几分钟后才发现。所以心跳机制的本质不是为了保持连接而是为了探测连接是否还活着。这个认知很关键面试时说出来立刻不一样。3.2 心跳该谁发、发多快、发什么面试官经常问心跳怎么设计这题没有标准答案但有几个原则你必须知道由客户端主动发。因为服务端面对的是海量连接让服务端给每个连接定时发心跳成本高且没必要。客户端发服务端回一来一回就验证了双向通路。间隔要小于中间设备的空闲超时。常见的NAT超时是60秒到5分钟不等所以心跳间隔一般设在30秒到60秒之间。设太长会被中间设备掐断设太短浪费流量和电量。心跳包要尽量小。WebSocket有ping/pong控制帧理论上可以用它做心跳但浏览器原生API不暴露ping/pong的发送接口所以前端一般发一个自定义的小消息比如{type:ping}来充当心跳。我实际项目里的做法是客户端每30秒发一次ping服务端收到立刻回pong客户端如果在两次心跳周期内没收到pong也就是60秒就判定连接已死主动关闭并触发重连。这个两次周期的容错设计是为了应对偶发的网络抖动避免一次丢包就误判。3.3 服务端怎么清理那些客户端已经跑了的连接这是面试里一个很实战的追问。客户端进程被杀、手机没电关机它不会发close帧服务端这边连接还挂着。如果不清理连接数会越积越多最后把服务端拖垮。标准做法是服务端也维护一套超时检测给每个连接记录最后一次收到数据的时间起一个定时任务扫描超过阈值比如心跳间隔的2到3倍没收到任何数据的连接直接强制关闭。这里要注意不能只依赖TCP的keepalive因为TCP keepalive的默认时间通常是2小时太长了而且它探测的是TCP层对应用层的假死无能为力。面试时如果你能补一句服务端的超时阈值要比客户端的心跳间隔大否则会出现客户端还在正常心跳、服务端却把它踢了的误杀面试官会觉得你是真踩过坑的。4. 断线重连重连不是断了就重连这么简单4.1 重连策略里的退避算法面试官问断线了怎么重连如果你答监听close事件然后重新new一个WebSocket那基本就停在入门水平了。真实场景要考虑的是重连风暴服务端重启几万个客户端同时断线如果它们都立刻重连服务端刚起来就被打挂然后又全断又全重连形成雪崩。解决办法是指数退避加随机抖动。第一次断线等1秒重连失败等2秒再失败等4秒、8秒一直退避到一个上限比如30秒之后每次都在上限附近重试。同时每次等待时间要加一个随机量比如在计算出的时间上乘以0.5到1.5之间的随机数这样几万个客户端的重连时间就被打散了不会同时涌上来。这个策略面试里几乎是必考你要能说出指数退避和随机抖动这两个词并且解释清楚为什么需要抖动。抖动的作用就是把同步的重连请求打散成异步的这是分布式系统里很通用的思路。4.2 重连之后之前的状态怎么办这是区分做过Demo和做过产品的分水岭。连接断了又重连中间这段时间的消息丢了怎么办重连后需不需要重新鉴权需不需要重新订阅我实际的做法是分三层处理鉴权层重连后必须重新走一次鉴权。因为服务端可能已经重启之前的会话状态没了。常见做法是把token放在连接建立后的第一条消息里发过去而不是依赖握手时的Cookie这样重连逻辑更统一。订阅层如果业务是订阅式的比如订阅某个房间的消息重连后要重新发送订阅请求。这里要做一个订阅状态管理把当前客户端订阅了哪些频道记在内存里重连成功后自动重放这些订阅。消息补偿层这是最容易被忽略的。重连期间服务端产生的消息客户端是收不到的。要解决这个需要服务端支持消息序号和拉取补偿每条消息带一个递增序号客户端重连后上报自己收到的最大序号服务端把之后的消息补发过来。这个机制在IM类产品里是标配。面试时如果你能主动提到消息补偿这个概念并且说清楚序号机制那这道题你就答到天花板了。4.3 怎么判断该重连还是该放弃不是所有断线都值得重连。如果服务端返回的是鉴权失败比如token过期你无脑重连只会一直失败白白消耗资源。所以重连逻辑里要区分可重试错误和不可重试错误。可重试的网络错误、服务端5xx、连接超时。不可重试的鉴权失败、协议错误、服务端明确返回的拒绝码。对于不可重试的错误应该停止重连走重新登录或者提示用户的流程。这个判断逻辑面试里能讲清楚说明你考虑过边界情况不是只会写happy path。5. 数据帧与粘包为什么你发的两条消息变成了一条5.1 WebSocket是基于消息的为什么还会有粘包问题这里有个常见的认知误区。WebSocket协议本身是面向消息的它用帧frame来划分消息边界理论上你发两条消息对方就收到两条不会像TCP那样粘在一起。所以严格来说WebSocket层面不存在TCP那种粘包问题。但是面试官问粘包的时候他真正想问的往往是应用层的消息分片和合并。有两种情况会导致你以为的粘包第一种是消息分片。WebSocket允许一条大消息拆成多个帧发送第一个帧FIN位为0最后一个帧FIN位为1。如果接收方没有正确处理分片把中间帧当成完整消息就会解析出错。第二种是应用层自己做了批量发送。比如你为了减少发送次数把多条业务消息打包成一个数组发出去接收方如果按单条消息解析自然就乱了。所以回答这个问题时你要先澄清WebSocket协议层不粘包然后再说应用层如果自己打包需要自己定义分隔或长度前缀。这个澄清动作本身就是加分项。5.2 帧结构里那几个关键字段面试官如果往深了问会问帧格式。你不用背全但几个关键位要记住FIN标识这是不是消息的最后一帧。1表示结束0表示后面还有帧。opcode操作码标识这是文本帧、二进制帧、还是控制帧close、ping、pong。Mask客户端发给服务端的帧必须掩码服务端发给客户端的不能掩码。这是协议强制要求目的是防止中间代理缓存污染。Payload length载荷长度7位、716位、764位三种编码方式按消息大小选择。其中掩码这个点经常被追问为什么要掩码。标准答案是防止恶意脚本通过构造特定字节序列来攻击有漏洞的中间代理。虽然现代代理基本都修了但协议保留了这个要求。你能说出这层说明你了解协议演进的历史背景。5.3 应用层消息设计的实战建议抛开协议实际项目里消息怎么设计面试官也很爱问。我的经验是统一消息信封每条消息都包一层包含type消息类型、seq序号、payload业务数据、timestamp。这样接收方先解析信封再根据type分发到不同的处理器。为什么要带seq前面讲重连补偿时提过序号是消息补偿的基础。为什么要带timestamp用于排查消息延迟和乱序。为什么要统一信封因为这样协议层和业务层解耦加新消息类型不用改解析逻辑。面试时你可以说我一般会定义一个统一的消息结构把类型、序号、时间戳都带上业务数据放在payload里然后解释每个字段的用途。这种回答比单纯讲协议细节更能体现工程能力。6. 和轮询、SSE的取舍什么时候不该用WebSocket6.1 三种实时方案的适用边界面试官问为什么用WebSocket不用轮询很多人只会说轮询浪费资源。这个答案太单薄。正确的答法是分场景讨论方案适用场景不适用场景短轮询消息频率低、实时性要求不高、实现简单优先高频消息、需要服务端主动推送长轮询需要一定实时性、但不想维护长连接连接数极大、服务端hold不住大量挂起请求SSE服务端单向推送、基于HTTP、自动重连需要客户端频繁上行、需要二进制传输WebSocket双向高频通信、需要低延迟只是偶尔推个通知、团队没有长连接运维经验你看WebSocket不是万能的。如果业务只是服务端偶尔推个通知给客户端SSE其实更合适因为它基于HTTP天然支持自动重连服务端实现也简单不用处理心跳和帧解析。面试时你能说出这种场景我会优先考虑SSE反而显得你判断力强不是技术崇拜。6.2 长连接的运维成本面试官很在意这一点很多人面试时想不到。WebSocket一旦上生产你要面对的是连接数上来了单机扛不住怎么办、多台服务端之间怎么广播消息、负载均衡怎么配置才能支持长连接、服务端发布时怎么优雅地让客户端重连。单机连接数受限于文件描述符和内存一般一台机器撑几万到十几万连接。要扩容就得引入网关层做连接保持业务层做逻辑处理中间通过消息队列通信。这样网关是无状态的相对而言可以水平扩展。负载均衡要选支持长连接的并且要配置连接空闲超时时间大于心跳间隔否则会被LB掐断。服务端发布时的优雅下线也很关键先停止接受新连接然后给所有在线客户端发一个我要下线了请重连的消息等客户端都重连到别的节点后再关闭。这个流程面试里能讲出来说明你参与过真实的上线运维。6.3 一个容易被忽略的点连接数不等于用户数面试官有时会问你们系统支持多少并发如果你直接答十万连接他可能会追问那十万用户同时在线吗。这里要区分连接数和活跃用户数。一个用户可能开多个标签页就有多个连接一个连接可能长时间不发消息只是挂着。所以容量规划时要看的是活跃连接的消息吞吐而不是单纯的连接数。十万个挂着的空闲连接和一万个每秒发十条消息的活跃连接对服务端的压力完全不是一个量级。这个区分能体现你对系统容量的理解深度。7. 面试里那些送命题的应对7.1 你项目里WebSocket QPS多少这题很阴因为很多人会随口报一个数。但面试官接着会问怎么测的瓶颈在哪怎么优化的。如果你没真测过立刻就露馅。正确的应对是如实说测过的部分没测过的说思路。比如你可以说我们压测过单机在保持五万连接的情况下消息吞吐大概每秒几千条瓶颈主要在消息序列化和广播时的遍历上后来把广播改成基于发布订阅的批量推送吞吐提升了一倍多。有具体数字、有瓶颈分析、有优化动作这就是真实经历的样子。如果你确实没做过压测也别硬编。可以说这块我们当时没做严格压测但我了解压测的思路是用工具模拟大量客户端连接逐步加压观察连接建立成功率、消息延迟和内存占用找到拐点。诚实加思路比编数字强。7.2 WebSocket怎么保证消息不丢这是个开放题没有银弹。你要分层回答传输层WebSocket基于TCPTCP本身保证可靠传输所以单条连接内不会丢包除非连接断了。连接层连接断了会丢消息靠前面说的序号加补偿解决。应用层如果业务要求强可靠需要ACK确认机制接收方收到消息后回一个确认发送方没收到确认就重发。但ACK会带来重复消息问题所以接收方还要做幂等去重一般用消息ID去重。这一套下来面试官会觉得你对可靠消息传递有完整认知。注意不要一上来就说WebSocket保证不丢那是错的连接断了照样丢。7.3 如果让你重新设计你会怎么改这种反思类问题面试官想看你的成长性。你可以挑一个真实踩过的坑讲比如早期我们没做心跳结果移动端切网络后大量僵尸连接堆积后来加了心跳和超时清理才解决。讲清楚问题现象、排查过程、最终方案比空谈架构强得多。我个人的体会是WebSocket这块面试背协议细节只能拿及格分讲清楚工程取舍和踩坑经验才能拿高分。面试官要的不是一个协议复读机而是一个知道什么时候该用、用了之后怎么维护的人。你把心跳、重连、补偿、容量这几块讲透基本就稳了。最后分享一个我自己的小习惯每次面完试我会把被问到的WebSocket相关问题记下来回头补自己答得不好的点。面了几轮之后你会发现翻来覆去就是那几个核心问题但每答一次你对长连接这件事的理解就深一层。这个东西真不是看几篇文章能速成的得自己动手搭一遍、踩一遍坑才能在面试里答得从容。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑