你点开一个网页,浏览器在几百毫秒内干了十几件事——先跟服务器握手,再发个GET /index.html,服务器把HTML吐回来,浏览器边解析边继续要CSS、JS、图片。这中间任何一步卡住,你看到的可能就是白屏或者转圈。web通信说白了就是客户端和服务器之间来回倒腾数据,但倒腾的方式、路径、代价,差别大了去了。
最早那会儿,HTTP就是个“请求-响应”的哑巴协议。你问一句,它答一句,答完就断。服务器根本记不住你是谁。后来有人往请求头里塞了个Cookie,服务器也学会在响应里写Set-Cookie,这才勉强有了“状态”。我当年第一次抓包看到Cookie: sessionid=abc123的时候,觉得这设计真够凑合的——把身份信息明文塞在每次请求里,跟把钥匙挂在门把手上差不多。但没办法,HTTP就是这么个无状态的东西,你不自己带身份,服务器就认不出你。
再往后,大家发现每次都要重新建立TCP连接太费劲。一个网页几十个资源,每个都三次握手,延迟叠加起来能急死人。HTTP/1.1 引入了 keep-alive,让连接可以复用。但问题没完——同一个连接上,请求还是得排队,前一个响应没回来,后一个就得等着。这叫队头阻塞。你想象一下超市只有一个收银台,前面的人掏零钱掏了三分钟,后面的人只能干瞪眼。后来有人搞出多路复用,HTTP/2 把请求切成帧,打上标签混在一起发,服务器再按标签拼回去。听起来很美,但实际部署里,很多老服务器和中间盒根本不认这套,降级回HTTP/1.1是常事。
WebSocket 是另一条路。既然HTTP每次都要重新带身份、重新协商,那干脆一开始就升级协议,建立一个全双工的TCP通道。客户端和服务器谁想说话就说话,不用等对方先问。聊天室、实时协作、股票行情,这些场景用WebSocket就顺多了。但代价是:你得自己管理连接状态,心跳保活、断线重连、消息顺序,全得写。我见过一个项目,WebSocket连接数一多,服务器内存直接爆掉,因为每个连接都占着一个文件描述符和一块缓冲区。后来他们改成了SSE(Server-Sent Events),只让服务器单向推,客户端用普通HTTP收,反而稳了。
说到SSE,它其实挺被低估的。就是一个Content-Type: text/event-stream的长连接,服务器可以源源不断往客户端发文本。不用像WebSocket那样搞协议升级,也不用处理二进制帧。浏览器原生支持EventSource,断线还会自动重连。做通知推送、日志流、AI对话的流式输出,SSE够用了。但很多人一上来就上WebSocket,觉得全双工才高级。实际上大部分场景,客户端根本不需要频繁往服务器推东西,单向足够了。
还有个东西叫HTTP/3,底层不用TCP了,换成QUIC(基于UDP)。为什么?因为TCP的队头阻塞在丢包时特别明显——一个包丢了,后面所有包都得等重传。QUIC把流分开,丢一个包只影响那一个流。而且QUIC把TLS握手也整合进去了,建连更快。但国内很多网络环境对UDP不友好,运营商限速、防火墙干扰,导致HTTP/3经常连不上,又降级回HTTP/2。我测过几个大站,开HTTP/3的失败率能到15%以上,最后还是得靠TCP兜底。
通信的安全层面,HTTPS现在基本是标配了。但别以为上了HTTPS就万事大吉。证书链验证、HSTS、CSP,这些配置稍微漏一个,中间人照样能插一脚。我见过一个内部系统,用了自签证书,客户端直接rejectUnauthorized: false,等于把锁挂在门上但没锁。还有更离谱的,把敏感token放在URL参数里,浏览器历史、服务器日志、Referer头,到处都留一份。web通信的安全,从来不是协议本身能全包的,得看写代码的人有没有那个意识。
说到底,web通信就是一堆权衡。延迟、吞吐、兼容性、开发成本,你不可能全都要。选HTTP/1.1还是HTTP/2,用WebSocket还是SSE,上QUIC还是老实TCP,得看具体场景。我自己的经验是:先跑通最简单的方案,遇到瓶颈再换。别一上来就追求“最新最好”,很多时候,一个简单的轮询就能解决的问题,硬上WebSocket反而给自己挖坑。
```