Chapter 01

htmx 哲学:HTML-first 与超媒体架构

理解 htmx 背后的设计哲学,重新认识 Web 的本质,掌握 HTML-first 开发方式

核心概念速览

REST(Representational State Transfer)
Roy Fielding 2000 年博士论文中提出的 Web 架构风格。REST 的六个约束之一是 HATEOAS,要求客户端通过服务器返回的超媒体(HTML 链接和表单)来驱动应用流程,而不是预先硬编码 API 路径。大多数"RESTful API"其实只实现了 REST 的一小部分,遗漏了 HATEOAS 这个核心约束。
HATEOAS(Hypermedia As The Engine Of Application State)
超媒体作为应用状态引擎。客户端无需预先知道 API 端点,而是通过服务器返回的 HTML 中的 <a href><form action> 来发现下一步可以做什么。这就是 Web 浏览器几十年来的工作方式。htmx 将这个原则延伸到 AJAX 请求场景。
SPA(Single Page Application)
单页应用。页面初始加载一个 HTML 空壳和大量 JavaScript,后续所有数据通过 Ajax/Fetch 以 JSON 形式获取,由前端 JavaScript 渲染成 DOM。React、Vue、Angular 应用都是 SPA 模式。优点是交互流畅,缺点是复杂度高、首屏慢、SEO 困难。
htmx
一个约 14KB 的 JavaScript 库,通过 HTML 属性(hx-gethx-posthx-target 等)扩展 HTML 的超媒体能力。核心思想:服务器返回 HTML 片段,htmx 将其插入到 DOM 指定位置,而不是服务器返回 JSON、前端 JavaScript 渲染。
HTML-first
一种 Web 开发哲学,强调 HTML 是构建 Web 应用的基础,而非 JavaScript。工具应该增强 HTML 的能力,而不是绕开它。渐进增强是其实践原则——页面在没有 JavaScript 时仍然可以基本工作。htmx 是 HTML-first 哲学的实践工具。
超媒体控制(Hypermedia Controls)
HTML 中允许用户与服务器交互的元素:链接 <a>(发出 GET 请求)和表单 <form>(发出 GET/POST 请求)。原生 HTML 的超媒体能力非常有限;htmx 把这种能力扩展到任意 HTML 元素和任意 HTTP 方法。

Web 的原始设计

Roy Fielding 与 REST 论文

2000 年,Roy Fielding 在他的博士论文《架构风格与基于网络的软件架构设计》中描述了 Web 的架构风格——REST(Representational State Transfer,表述性状态转移)。其中一个关键约束是 HATEOAS(超媒体作为应用状态引擎)

HATEOAS 的核心思想

客户端通过服务器返回的 HTML 中的超链接(<a href><form action>)来发现下一步可以做什么,而不是通过预先内置的知识。HTML 文档本身驱动应用的状态转换,这就是超媒体作为状态引擎的含义。

这就是 Web 最初的工作方式:浏览器请求一个 URL,服务器返回 HTML,HTML 中包含下一步操作的链接和表单,用户点击或提交,服务器处理并返回新的 HTML……整个应用流程完全由 HTML 驱动。

SPA 的兴起与代价

2010 年代初,Gmail 等 Single Page Application(SPA)证明了丰富的浏览器端交互体验的可能性。随后 Backbone.js、Angular、React、Vue 相继出现,SPA 成为现代 Web 开发的主流范式。

但 SPA 带来了显著的复杂度:

Carson Gross 在 htmx 的官网 essay 中写道:"大多数 Web 应用不需要 SPA 的全部复杂性。如果我们把超媒体的能力还给 HTML,让 HTML 做它本来就应该做的事,很多应用可以极大地简化。"

htmx 的核心思想

扩展 HTML 而非替代 HTML

htmx 的设计哲学是:扩展 HTML 的能力,而不是替代 HTML。原生 HTML 有三个限制:

  1. 只有 <a><form> 才能发出 HTTP 请求(其他元素不行)
  2. 只有 GETPOST 方法(PUT/DELETE/PATCH 无法在 HTML 中使用)
  3. 请求总是替换整个页面(无法局部更新)

htmx 通过 HTML 属性消除了这三个限制:

服务器返回 HTML,而非 JSON

维度传统 SPA 方式htmx 方式
服务器响应JSON 数据HTML 片段
前端职责接收 JSON,渲染 UI,管理状态发出请求,htmx 更新 DOM
状态管理前端 Store(Redux/Zustand)服务器是状态的唯一来源
模板引擎前端 JSX/模板(React/Vue)服务端模板(Jinja2/Go tmpl)
JS 代码量大量(框架 + 业务逻辑)极少或零
适合场景高交互性应用(在线编辑器、游戏)内容驱动应用(博客、管理后台)

安装 htmx

CDN 引入(最简单)

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/htmx.org@2.0.0"></script>
</head>
<body>
  <!-- 所有 hx-* 属性现在都可用了 -->
  <button
    hx-get="/api/greeting"
    hx-target="#result"
  >
    获取问候
  </button>
  <div id="result"></div>
</body>
</html>

npm 安装(与构建工具集成)

# npm
npm install htmx.org

# 在 JS 入口文件中引入
import 'htmx.org';

第一个 htmx 示例

完整示例:点击按钮加载内容

<!-- 前端 HTML -->
<button
  hx-get="/api/users"
  hx-target="#user-list"
  hx-swap="innerHTML"
  hx-trigger="click"
>
  加载用户列表
</button>

<div id="user-list">
  <p>点击按钮加载用户...</p>
</div>
# 服务器端(Python FastAPI)
from fastapi import FastAPI
from fastapi.responses import HTMLResponse

app = FastAPI()

@app.get("/api/users", response_class=HTMLResponse)
async def get_users():
    # 返回 HTML 片段,不是 JSON!
    users = await db_get_users()
    html = "<ul>"
    for user in users:
        html += f'<li>{user.name} ({user.email})</li>'
    html += "</ul>"
    return html
检测是否为 htmx 请求

htmx 发出的请求会携带 HX-Request: true 请求头。服务器可以通过检查这个头来区分完整页面请求和 htmx 局部请求,返回不同的响应(完整 HTML 页面 vs HTML 片段)。

htmx 请求生命周期

理解 htmx 请求的完整生命周期,有助于调试问题和利用事件系统:

htmx 请求生命周期 ──────────────────────────────────────────────── 用户事件(点击/键入/etc) ↓ htmx:beforeRequest(可取消) ↓ 发出 AJAX 请求 → 服务器处理 ↓ 收到响应 ↓ htmx:beforeSwap(可修改 shouldSwap) ↓ DOM 更新(swap) ↓ htmx:afterSwap ↓ htmx:afterSettle(动画结束后)

每个阶段都可以通过 JavaScript 监听事件进行干预。例如:在 htmx:beforeRequest 中显示加载动画,在 htmx:afterSettle 中隐藏;在 htmx:beforeSwap 中允许 422 错误响应也更新 DOM;在 htmx:afterSwap 中重新初始化第三方库。

htmx 与 AJAX 的历史

htmx 并不是第一个用 HTML 属性实现 AJAX 的库。它的精神先祖是 intercooler.js(也是 Carson Gross 创建的),而更早则可以追溯到 2005 年 Jesse James Garrett 提出的 AJAX 技术。htmx 2.0 发布于 2024 年,移除了对 IE11 的支持,全面拥抱现代浏览器 API。

什么时候该用 htmx,什么时候不该用

htmx 适合的场景

  • 内容管理系统、博客、文档站点
  • 管理后台(CRUD 操作为主)
  • 电商网站(商品列表、购物车)
  • 社区/论坛(帖子列表、评论)
  • 需要 SEO 的内容页面
  • 小团队/全栈开发者,不想维护独立前端
  • 现有 Server-Side Rendered 项目渐进增强

应该选 React/Vue 的场景

  • 在线代码编辑器、白板、设计工具
  • 复杂实时协作应用(Google Docs 类型)
  • 游戏、动画密集型交互
  • 离线优先的 PWA 应用
  • 大量客户端状态(复杂表单联动)
  • 已有大型前端团队和 React 基础设施
htmx 不是万能的

htmx 不适合高度交互的应用(在线编辑器、游戏、复杂仪表板)。如果用户操作需要立即的本地响应(不能等待服务器往返延迟)、需要大量客户端状态、或需要离线工作,React/Vue 是更合适的选择。选择 htmx 是一种架构权衡,而非信仰。

htmx 2.0 的关键变化

htmx 2.0 于 2024 年发布,相比 1.x 有几个重要变化:

本章小结

htmx 的核心要点:① htmx 是对 HTML 的扩展,而非替代——它让任何 HTML 元素都能发起 AJAX 请求,实现局部页面更新;② HATEOAS 是 Web 的原始设计,htmx 将其发扬光大;③ 与 SPA 的根本区别在于:htmx 让服务器返回 HTML,前端只负责 DOM 更新,而 SPA 让服务器返回 JSON、前端负责渲染——这意味着模板在服务端维护,不需要前端状态管理;④ htmx 引入一个 CDN 链接即可使用,没有构建工具依赖;⑤ 通过 HX-Request: true 头判断 htmx 请求,同一路由可以为全页请求和 htmx 请求返回不同内容;⑥ 适合内容驱动应用(CMS、后台、电商),不适合高度交互应用(在线编辑器、游戏)。