文章摘要
本文介绍了一种名为“HTML over WebSockets”的SPA构建新思路:服务器直接发送已构建好的HTML,客户端仅负责放置,无需JSON接口和前后端契约,所有渲染逻辑集中在后端,通过WebSocket实现实时双向通信。
文章总结
核心观点:用WebSocket传输HTML,构建极简JavaScript的实时单页应用
传统单页应用(SPA)开发模式复杂:需要JavaScript框架渲染视图、JSON API提供数据,以及前后端两套独立代码库通过接口协议协作。本文提出另一种方案——HTML over WebSockets,即服务器直接发送已构建好的HTML片段,客户端仅负责将其放置在正确位置。所有渲染逻辑保留在后端,使用单一语言,无需API接口或协议约定。
三种传输变体
- HTTP:逐请求传输(如htmx、Unicorn)
- SSE(服务器推送事件):单向持续通道(如Datastar)
- WebSocket:永久双向通道(如Phoenix LiveView、Django LiveView)
技术起源
2019年ElixirConf上,Chris McCord演示了Phoenix LiveView技术,15分钟内用纯后端代码构建了实时Twitter克隆,无需任何前端渲染JavaScript或流行框架(React/Angular/Vue)。此后该模式被移植到多种语言。
工作原理
- 客户端:JavaScript仅负责建立WebSocket连接、接收HTML并插入DOM,以及处理动画、事件等次要任务
- 服务器:承担全部渲染逻辑,直接生成HTML并通过WebSocket推送
- 优势:无需JSON中间层,服务器可主动推送更新,状态保存在服务端
核心优势
- 单一渲染引擎:降低复杂度
- 无需构建API:服务器直接生成HTML
- 服务端状态管理:每个连接客户端有独立进程维护状态
- 直接数据库连接:无需JSON/GraphQL中间层
- 真正实时:客户端即时接收变更
- 广播能力:可同时向所有连接客户端推送更新
- 更低延迟:持久连接避免重复TCP握手和HTTP头部开销
- 极简JavaScript:无需React等重型框架
- 合理SEO:首屏HTML由服务端渲染,可被索引
- 防注入:HTML在服务端转义后传输,XSS攻击无效
主要缺点
- 服务端资源消耗大:需维护WebSocket连接和客户端状态,水平扩展需共享状态(如Django需Channels+ASGI+Redis)
- 物理延迟影响体验:高延迟下"即时"感会下降
- 无法离线工作:断连时网站停止运行,需设计重连机制
- 学习曲线陡峭:运行WebSocket服务器和掌握LiveView模式需要学习成本
现有框架生态
| 语言 | 框架 | 传输方式 | 服务器推送 | 状态 | |------|------|----------|------------|------| | Elixir | Phoenix LiveView | WebSocket | 是 | 成熟(1.x,2024年12月发布1.0) | | Ruby | Hotwire (Turbo+Stimulus) | HTTP+WebSocket/SSE | 是 | Turbo 8支持morphing | | Python/Django | Django LiveView | WebSocket | 是 | 活跃开发中 | | Python/Django | Reactor | WebSocket | 是 | 活跃 | | Python/Django | djust | WebSocket | 是 | 新项目,使用Rust VDOM | | Python/Django | django-unicorn | HTTP/AJAX | 否 | 活跃 | | Python/Django | Tetra | AJAX+WebSocket | 是 | 较新,基于Alpine.js | | C#/.NET | Blazor (Interactive Server) | WebSocket (SignalR) | 是 | .NET 9,支持渲染模式 | | PHP/Laravel | Livewire 3 + Reverb | WebSocket | 是 | 2024年推出自有WebSocket服务器 | | 通用(JS) | htmx | HTTP+WS/SSE扩展 | 是(扩展) | 2.0 | | 通用(JS) | Datastar | SSE | 是 | 1.0 |
SSE:低成本替代方案
当通信主要为服务器到客户端(如通知、实时数据流、AI响应)时,SSE是更简单的选择: - 优点:基础设施简单,无需维护状态进程,易于负载均衡和扩展 - 局限:单向通信(客户端需另发HTTP请求)、仅支持文本、不适合双向密集交互
选择原则: - 需要双向低延迟通信(聊天、协作编辑、游戏)→ WebSocket - 仅需服务器推送 → SSE - 请求-响应模式足够 → htmx over HTTP
核心启示
HTML over WebSockets并非万能方案,但核心思想值得借鉴:发送HTML而非JSON,使用单一语言,消除API接口、协议约定和一半的前端代码。信任良好的架构设计,而非追逐流行框架或模式。
评论总结
根据评论内容,主要观点和论据总结如下:
支持观点(认可度较高): - 通过WebSocket传输HTML可简化架构,减少HTTP开销。引用:"Less traffic and less latency per action: a single persistent connection avoids repeating the TCP handshake and the HTTP headers on every interaction."(评论10) - 适合内部工具或快速原型开发。引用:"The server-side Blazor approach is for an internal web application... It's not an 'industrial strength' web application... It's also a joy to work with."(评论30) - 类似技术(如Phoenix LiveView、HTMX)已获实践验证。引用:"Close but htmx with SSE and dom swaps and morphing gets you there without reinventing any wheels."(评论8)
反对观点(认可度较高): - 技术冗余,传统HTTP已足够。引用:"Is this satire? Rage bait? Why would you ever do this? Just make a normal website!! You've invented an MPA with extra steps!"(评论1) - 存在安全风险(XSS)和性能问题(如输入焦点丢失)。引用:"input elements lose focus, if some view was scrolled, then it gets unscrolled, jumping under user's pointer etc."(评论15) - 违背前后端解耦原则。引用:"The whole concept of decoupling the frontend and the backend is that they can be agnostic of each other... Serve rendered html like in 2000 and you have recreated a smart way to do what industry spent decades running away from."(评论26)
中立/历史视角: - 技术循环重现。引用:"Love how DHTML, ASP.NET Ajax, JSF Ajax kind of keeps being re-invented."(评论6) - 需根据场景选择工具。引用:"The right solution to your problem often involves understanding the problem you're trying to solve!"(评论30)