互联网博客文章查询

Hacker News Top 新闻

摘要

本文以X对Nitter采取法律行动为例,探讨了互联网上封闭API和围墙花园的问题,并倡导采用atproto和activitypub等开放协议,以促进去中心化社交网络的发展。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/08/28 00:23

# SELECT * FROM internet.blogposts 来源:https://pfrazee.leaflet.pub/3mu3p2smmis22 2007年,蒂姆·伯纳斯-李撰写了《巨型全球图谱》(https://www.panarchy.org/berners-lee/graph.html)一文。文中写道: > 内心深处的呼唤……渴望我的友谊、与他人的联系,能够超越文档与网站的界限……那么,任何其他网站或程序都可以使用这些信息。 在X(原Twitter)向Nitter(https://techcrunch.com/2026/08/25/x-sends-cease-and-desist-to-open-source-project-nitter-over-alleged-scraping/)发送停止并终止函之际,重读TBL的这篇文章显得尤为贴切。Nitter——曾经是——一个简单的X前端界面,允许用户无需登录即可查看推文。即便是这种轻微的代理页面访问,也足以招致法律威胁。 2007年,Twitter的API以开放著称,这意味着成千上万的开发者可以免费构建客户端、工具和分析服务。那么,后来发生了什么?为何API被收紧?原因很简单:网络效应取胜了。开发者不再被视为资产,API逐渐封闭。先是速率限制、分级定价、登录要求,然后是技术手段封锁变通方法,而现在是律师函。Meta在十年前也上演了同样的剧本,以至于如今人们很难记得曾经有过值得基于其构建应用的Facebook或Instagram API。 正因如此,互联网档案馆创始人布鲁斯特·卡利十多年来一直呼吁我们"锁定开放的网络"(https://blog.archive.org/2015/02/11/locking-the-web-open-a-call-for-a-distributed-web/)。 Nitter最初使用的是X的API。当API关闭后,它转而读取公开的网页。而如今,当已经无物可关时,X的要求是让其源代码下架。一个用于展示公开帖子的程序,正被当作计算机犯罪法规下的规避设备对待。 我们面临的是一个围墙花园的问题。这不会改变,而我们面前唯一的选项是重新开始。 好消息是,atproto(https://atproto.com/)持续增长(https://npmx.dev/package-stats/@atproto/syntax/v/0.7.5?end=2026-08-26&start=2025-08-28&granularity=monthly),ActivityPub(https://activitypub.rocks/)依然坚韧,我们的社区中充满了对开放社交网络的信仰者和建设者。由于我参与atproto的工作,接下来我将以此为重点。 ### 通过 `SELECT *` 实现互操作(https://pfrazee.leaflet.pub/3mu3p2smmis22#interoperation-by-select) ``` SELECT * FROM internet.blogposts ``` 围墙花园的问题源于一个简单的问题:我如何执行 `SELECT * FROM internet`? 如果你从未编写过数据库代码,`SELECT * FROM users` 是请求数据库返回其关于用户的所有信息的语句。一旦获取,你就可以对其进行过滤、排序,并将其与你拥有的任何其他数据连接。 历史上,网络并非如此运作。网络由几十家公司组成,每家都持有自己的数据柜,门前都有一位接待员。他一次只能为你读取一个文件,而且只限于你能准确说出的文件,按他的速度读取,且仅在其老板允许的情况下。 Nitter曾是一个轻量级的X阅读器,运作良好,直到X关闭了它所依赖的访问。每一个API(即那位“接待员”)都是一项尚未被推翻的商业决策。 但无常并非唯一的问题。即使一个永久、免费、慷慨限速的API也不够。应用程序需要比API能提供的更有意义的访问权限。 - 你只能提出别人已经想到并准备好答案的问题。API是一个固定菜单。它提供 `getPosts(user)` 和 `getFollowers(user)`。如果你的产品构想需要“我关注的人所关注的人的帖子,按被引用频率排序”,没有这样的端点,也永远不会有,因为那家公司没有人在为你的产品开发。 - 即使是正确的问题,也以错误的格式返回。关注者每批返回100个。一个拥有两百万关注者的账号需要进行20,000次往返请求。在任何合理的速率限制下,回答关于一个用户的一个问题就需要数小时——因此,任何需要即时感的交互式应用,在你开始之前就被排除了。 - 你无法跨“柜子”进行连接。有趣的问题几乎总是跨服务的:这个人的帖子与那个人的照片,与第三个服务的评价。两栋楼里的两个接待员无法交叉引用任何信息,你也同样做不到。 - 你无法索引你不持有的数据。搜索、排序、推荐、信息流、审核工具——所有这些都建立在对整体语料库的索引之上,这些索引是为你产品的特定问题而布局的。你无法通过钥匙孔来构建索引。 要真正构建一个服务,我们需要整个数据集,而不仅仅是对它的视图;我们需要它是实时的,在数据变化时到达,而不是轮询获取;我们需要按照我的产品需求对其进行索引;我们需要能够写回数据;并且我们需要所有这一切得到保证,不会因任何一家公司的季度优先级变化而撤销。 桌面应用通过共享文件系统来处理这个问题。互联网应用不使用文件;它们使用数据库。我们需要共享数据库。 作为一名用户,我不想被锁定在某个应用里,就像我不想被锁在汽车后备箱里一样。我想要一个真正的自由市场。 因此,以下是另一组需求。 - 身份的持久性。我的存在和关系是围绕我的身份建立的。它需要比我注册的应用程序存活更久。 - 在服务间导出活跃的(而非静止的)数据。导出你的推文存档作为账户迁移方案是无用的,因为数据并非孤立存在。如果数据不再具有可操作性——即无法被网络中的参与者进行额外操作——那么它就是一个静态存档,对另一个应用毫无用处。你当然可以打印出你的推文看看。 如果我们希望数据在原始服务之外仍然可操作,那么我们需要共享数据库。 所有这些问题都是atproto旨在解决的,包括开放的数据访问、账户迁移以及实时的网络活动数据流。 ### atproto 如何实现 `SELECT * FROM internet`(https://pfrazee.leaflet.pub/3mu3p2smmis22#how-atproto-makes-select-from-internet-happen) 我们如何共享数据库?我们并不共享单个数据库。我们共享许多数据库。我们创建了一个由个人数据服务器(PDS)组成的网络,应用程序与之交互。 我们如何处理应用程序向我们的个人数据服务器发送复杂的 `SELECT *` 查询?我们不直接处理。我们复制日志上的数据。我们让每个应用程序聚合数据副本,在本地进行查询。 我们如何让应用程序写入这些数据库?在这种情况下——我们确实如此!我们让应用程序将写操作发送给PDS,PDS再将其复制回其他应用程序。 最后一点是atproto核心直觉所在:写入/摄取循环。几乎每个atproto应用都有类似这样的代码: ``` // 写入 pds.putRecord(post) // 摄取 onPut(‘app.bsky.feed.post’, evt => { mydb.put(‘posts’, {...}) }) ``` 你不必等待数据通过线路传回摄取,可以使用“短路”方式,让你的应用数据库更快更新。来自PDS的200 OK是事务性的确认。 因此,更高效的模式看起来更像这样: ``` // 写入 pds.putRecord(post) mydb.put(‘posts’, {...}) // ← 乐观更新 // 摄取 onPut(‘app.bsky.feed.post’, evt => { mydb.put(‘posts’, {...}) }) ``` ### 它有效吗?(https://pfrazee.leaflet.pub/3mu3p2smmis22#does-it-work) 有效。这个网络已经存在。它是活跃的、公开的,你现在就可以从一台笔记本电脑上读取所有内容——无需征得任何人的许可。这正是 Bluesky (https://bsky.app/)、Tangled (https://tangled.org/)、Leaflet (https://leaflet.pub/) 以及众多其他应用 (https://atstore.fyi/) 目前的工作方式。 让我给你一些数据。在撰写本文时: - atproto 上有 4610 万个账户 - 245 亿条记录,其中 31.5 亿是帖子,174 亿个是点赞 - 每秒 500-1000 次写入事件 - 超过 5000 个个人数据服务器 通过新的 jetstream 服务 (https://bsky.network/),访问数据从未如此简单。 ``` import { Jetstream, isCreate } from '@bsky/jetstream'; import { app } from '@bsky/sdk/lexicons'; const jetstream = new Jetstream('https://jetstream.us-east.bsky.network'); const collections = [app.bsky.graph.follow, app.bsky.feed.repost, app.bsky.feed.post]; for await (const event of jetstream.live({ collections })) { if (isCreate(event, app.bsky.graph.follow)) { console.log(`🌱 ${event.did} 关注了 ${event.commit.record.subject}`); } else if (isCreate(event, app.bsky.feed.repost)) { console.log(`♻️ ${event.did} 转发了 ${event.commit.record.subject.uri}`); } else if (isCreate(event, app.bsky.feed.post) && event.commit.record.reply) { console.log(`💭 ${event.did} 回复了 ${event.commit.record.reply.parent.uri}`); } } ``` 如果你想快速上手,可以在这里尝试 (https://bsky.network/)。 ### 别再收到停止并终止函了。改用 `SELECT * FROM internet.blogposts`(https://pfrazee.leaflet.pub/3mu3p2smmis22#stop-getting-cease-desists-select-from-internetblogposts-instead) 哦,如果你在 atproto 上专门寻找博客文章,你可能想使用 standard.site (https://standard.site/)。 👉在 Bluesky 上关注我。(https://bsky.app/profile/pfrazee.com)

相似文章

基于ATProto构建

Hacker News Top

Luke Kanies讨论了他在ATProto上构建一套去中心化评论应用的计划,分享了来自Local First Conference的反馈,并对该协议当前的发展方向提出了批评。

在 ATProto 之上运行 ActivityPub

Hacker News Top

本文建议在 AT Protocol 的 PDS 之上运行 ActivityPub,认为结合两种架构可以在保持与现有联邦式社交媒体兼容性的同时,提供更好的用户自主权和可信退出机制。

我们曾经拥有的(互联网XMPP全盛时期)(2023)

Lobsters Hottest

一篇回顾性的博客文章,感叹XMPP(Jabber)从2008年左右的全盛时期(当时被广泛使用并得到Google和Facebook等主要平台的支持)走向衰落,并与Matrix等现代去中心化替代方案进行对比。作者反思了XMPP如何曾经通过Pidgin和Trillian等客户端为主流用户所用,但后来被专有的围墙花园式消息应用所取代。

实现ActivityPub为何困难,又为何不必如此

Lobsters Hottest

本文解释了实现ActivityPub协议的复杂性,例如处理多种HTTP签名标准和JSON-LD上下文,并介绍了Fedify,这是一个旨在简化构建ActivityPub应用的TypeScript框架。