返回

文章详情

Datasette 应用:在 Datasette 中托管自定义 HTML 应用

Hacker News2026年6月19日 01:06

2026年6月18日,今天我们推出了一个新的 Datasette 插件:datasette-apps,并在 Datasette 项目博客上发布了这个启动公告。这篇文章中有关于插件的详细信息,但我想在这里扩展一下,以提供更多背景。简而言之,Datasette 应用是自包含的 HTML + JavaScript 应用,它们在一个严格限制的 <iframe> 沙箱中运行,该沙箱托管在您的 Datasette 应用程序上。它们可以使用 JavaScript 对 Datasette 中的数据进行只读 SQL 查询,如果您配置了一些存储查询,它们也可以运行写查询。这里有一个非常简单的示例和一个更复杂的自定义时间线示例——后者看起来是这样的:应用程序可以运行 JavaScript 并渲染 HTML 和 CSS。它们在访问方面受到限制——它们运行的 <iframe sandbox="allow-scripts allow-forms"> 阻止它们访问 cookies 或 localStorage,并且它们还具有一个注入的 CSP 头(得益于这项研究),这使它们无法向外部主机发出 HTTP 请求,从而防止恶意或有缺陷的应用程序 exfiltrate 私密数据。Datasette 应用最初是我尝试为 Datasette Agent 构建 Claude Artifacts 机制,但我很快意识到沙箱模式的潜力远不止于将自定义应用添加到界面表面,并将其提升为 Datasette 生态系统中的一个顶级概念。它们也是将我多年的 vibe-coded HTML 工具实验转变为我主要项目的核心功能的有趣方式!您可以通过使用 GitHub 登录到 agent.datasette.io 演示实例来尝试 Datasette 应用。为什么要构建这个?自首个版本以来,Datasette 一直为通过其 JSON API 创建自定义 HTML 应用提供灵活的后端。我早期的 Datasette 项目之一是我在 Eventbrite 工作时为文档制作的内部搜索引擎——它通过定期将来自不同系统的文档导入到 SQLite 中,然后通过具有自定义 HTML + JavaScript 搜索的 Datasette 实例提供服务,直接查询 Datasette API。我在客户端使用 JavaScript 构建 SQL 查询,最初是作为工程笑话,但结果证明这是一种非常有效的迭代应用的方法!该项目,加上我在构建 HTML 工具集合的经验和与 Claude Artifacts 的实验, convinced我增加一个 Datasette 风格的后端与自包含的 HTML 前端的组合是极其强大的。想象一下,如果 Claude Artifacts 可以访问持久的关系数据库,它们会变得多么有用。这就是我与 Datasette 应用一起构建的内容!Datasette 应用中的有趣想法以下是我在构建此应用时发现的一些想法和模式,我认为它们会有持久的价值。<iframe sandbox="allow-scripts" srcdoc="..."> + <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:;">这就是使 Datasette 应用在首先能够实现的魔力组合。我需要在一个高度敏感的域上运行不受信任的 HTML 和 JavaScript——经过身份验证的 Datasette 实例可以包含各种私密数据。sandbox= 属性让我以无法与父应用交互的方式运行不受信任的代码——它无法读取 DOM,或访问 cookies,或从 localStorage 中窃取秘密。然而,它可以使用 fetch() 等加载内容(或 exfiltrate 数据)来自其他域。但是……事实证明,如果您使用 <meta http-equiv="Content-Security-Policy"> 头部来启动 HTML 页面,则可以设置额外的策略,以锁定对其他域的访问。我担心恶意 JavaScript 会能够更新或删除该头部,但结果证明这是行不通的——一旦设置,CSP 策略对于该帧的内容是不可变的。通过 postMessage() 和 MessageChannel() 锁定 API在将这些 iframe 锁定到无法进行任何有趣的操作之后,挑战是在它们能够执行一个允许列表中的操作的基础上重新打开它们,从只读 SQL 查询开始。我使用 postMessage() 构建了这个的第一个版本,它允许子 iframe 向父窗口发送消息。我创建了一个简单的协议,请求父级运行 SQL 查询——然后父级可以验证它是否针对允许列表中的数据库执行。某个 LLM 工具,我记得是 GPT-5.5,建议单独使用 postMessage() 可能会被利用,如果 iframe 以某种方式从不受信任的域加载了额外的代码。我认为这不适用于 Datasette 应用,但我也相信深度防御,因此我让 GPT-5.5 帮我转换为基于 MessageChannel() 的传输。MessageChannel() 的优点是,如果页面导航到其他地方,频道会自动关闭,从而消除了执行来自不受信任的外部发送的命令的可能性。

赞助内容

NordVPN Next-gen Antivirus

本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。

请我喝杯咖啡