返回 2026-05-10
⚙️ 工程

我不会在你的 URL 中添加查询字符串I Will Not Add Query Strings to Your URLs

susam.net·2026-05-09

作者 Chris Morgan 强烈反对在 URL 中使用查询字符串(query strings),认为它们是 Web 上的一个误设计。他主张使用路径(path)来传递参数,因为路径更符合 URL 作为资源标识符的本质,且更易于阅读、调试和缓存。文章回顾了 Web 早期的发展,并指出查询字符串虽然方便,但带来了诸如 SEO 问题、URL 长度限制和安全风险等弊端。

作者 Susam Pal,2026年5月9日

昨晚,我的阅读器里出现了一篇简短的博客文章,感觉就像是在直接对我说话。这是 Chris Morgan 的一篇精彩博文:《我禁用了查询字符串》。

目录

  • 网络智慧
  • 网络漫游
  • 功能缺陷
  • 损坏的 URL
  • 疑虑
  • 结论
  • 网络智慧

    Chris 是我大约五年前开始阅读其互联网评论的人。我第一次注意到他,是因为他在 Hacker News 上对我的一个 CSS 规则集合给出了非常详细的反馈。我绝对算不上是一名网页开发者。我的职业生涯大部分时间都在用 C 和 C++ 做系统编程。然而,开发网站、编写小型 HTML 工具一直是我多年的爱好。我主要通过自学掌握了网页开发技能:先是研究早期 2000 年代我喜欢网站的源代码,后来偶尔会突然想实现一个新游戏或工具,于是查阅 MDN Web 文档来学习所需的一切。但这种方式学习的问题在于,你有时会养成一些时髦但不一定最优甚至不正确的方法和习惯。所以当 Chris 评论我的 CSS 样板代码时,我觉得非常有价值。他的建议帮助我大幅提升了 CSS 水平。事实上,他的一些观点我一直铭记在心——每当我做一个业余的 HTML 项目时都会想起:始终保留链接的下划线,并为已访问的链接保留紫色。

    自那以后,我一直在关注 Chris 关于网络相关主题的文章和评论。他经常在网页相关的项目中发表精彩的反馈。每当他发布一篇,我都会仔细阅读,即使项目不是我的。每次都能从他那里学到一些有趣且实用的东西。这里有一个最近的例子,来自 Lobsters 上的故事:《为 RSS 添加作者上下文》。

    网络漫游

    几个月前,我创建了一个名为 Wander Console 的新项目。这是一个小型、去中心化、可自托管的网页控制台,允许访问者探索由独立个人网站所有者组成的社区推荐的有趣网站和页面。例如,我的控制台在这里:susam.net/wander/。如果你点击那里的“Wander”按钮,该工具会加载 Wander 社区推荐的一个随机个人网页。

    这个工具由一个 HTML 文件和一个 JavaScript 文件组成,前者实现了控制台界面,后者由网站所有者定义邻居控制台的列表以及他们推荐的网页列表。只要将这两个文件复制到你的 Web 服务器上,就能立即在 Web 上运行一个活跃的 Wander 控制台。你不需要任何服务端逻辑或软件,只需要一个基本的 Web 服务器即可运行 Wander Console。你甚至可以将其托管在受限环境中,比如 Codeberg Pages 或 GitHub Pages。当你点击“Wander”按钮时,控制台会连接到其他远程控制台,获取网页推荐,随机选择其中一个并在你的浏览器中加载。它有点像现已停服的 StumbleUpon,但它是完全去中心化的。它又有点像网页环,不同的是社区网络不限于循环结构;它是一个灵活的图状网络。

    目前有超过50个网站托管此工具,它们共同推荐了1500多个网页。你可以通过 susam.codeberg.page/wcn/ 查看已知控制台及其推荐页面的最新快照。如需了解该工具的更多信息或将其部署到你的网站,请访问 codeberg.org/susam/wander。

    误加功能

    如果你好奇为什么我在上一节突然将项目关联到这篇文章,那是因为我最近为该项目添加了一个我自己也不太确信是否合适的可疑功能。而这个“误加功能”正是本文要讨论的内容。

    在 Wander Console 的 0.4.0 版本中,我增加了对加载网页时 via= 查询参数的支持。例如,当你在 susam.net/wander/ 使用控制台时访问了 midnight.pub,控制台会通过以下 URL 加载页面:

    https://midnight.pub/?via=https://susam.net/wander/

    这使得被推荐网站的所有者可以通过访问日志得知此次访问来自一个 Wander Console。Chris 最近的博客文章就批评了这类功能。他写道:

    我不喜欢人们在 URL 中添加追踪信息。更不喜欢的是,有人在我的 URL 里添加追踪信息。 https://chrismorgan.info/no-query-strings?ref=example.com? 我同意吗?如果我想知道,我会去看 Referer 头部;如果没有,那很可能有它的道理。你把这种东西加进链接里,是在滥用用户。

    我之前提到过,我对添加引荐查询字符串这件事并不完全确信。但我还是加了,这是为什么?因为我屈服于大众的需求。让我简要描述一下我当时考虑并实现这个功能时的心理状态。当我第一次在 Codeberg 上看到这个功能请求时,我的第一反应是犹豫。我不认为这是个好功能。但当时我正在忙于代数图论的研究,另一个新爱好也临近截止日期,没有太多时间能冷静思考。事实上,Wander Console 的所有功能都是在从研究中短暂休息时匆忙完成的。我第一次编写控制台大约花了一个半小时,那是个清晨,我的大脑已经疲惫到无法继续阅读代数图论文献,急需休息。在另一次这样的休息中,我重新审视了这个功能请求,尽管心存疑虑,最终还是决定实现它。而这一次休息,我正在写这篇帖子。

    通常来说,我不喜欢在自己的小项目中添加过多新功能。我希望它们保持有限的范围,并随着时间的推移变得稳定。当一个项目满足了最初设定的基本需求后,我就认为它已经完成,不再添加任何新功能。当然,我会修复 bug。但我并不喜欢无休止地添加新功能。这是我的业余项目维护风格。因此,忽略为控制台加载的 URL 添加引荐查询字符串的请求对我来说本该轻而易举。但我认为,长期高强度研究工作带来的身心疲惫确实影响了我。

    尽管我的直觉告诉我这不是个好功能,但我当时无法明确说出原因。于是我还是实现了这个引荐查询字符串功能。在实现过程中,我为配置添加了一个禁用机制,这样如果有人不喜欢这个功能,就可以自行关闭它。这又是一个错误决定。像这样的可疑功能根本不该实现,如果非要实现,也应该做成“主动启用”而非“被动禁用”。由于我没有太多时间仔细思考这个功能的后果,我只是草率地直接实现了它,而没有深入批判性思考。正如《侏罗纪公园》那句名言所说:

    你们的科学家总是忙着纠结能不能做到,却从不停下来想想该不该做。

    损坏的 URL

    很快我就发现我的直觉是对的。实现这个功能后,我最喜欢的一个页面在控制台里加载失败了。为了说明问题,这里有两个相似但略有不同的 URL:

  • https://int10h.org/oldschool-pc-fonts/fontlist/
  • https://int10h.org/oldschool-pc-fonts/fontlist/?foo
  • 第一个 URL 可以正常加载,但第二个返回 HTTP 404 错误页面。因此,当我的工具向第一个 URL 添加了 via= 查询参数后,页面就无法加载了。后来有了更多时间和反思,我终于能清楚地解释为什么在一个正常工作的 URL 上添加引荐查询字符串是个糟糕的主意。修改一个 URL 就会得到一个新的 URL。新 URL 可能指向完全不同的资源,甚至根本不指向任何资源——哪怕改动只是添加一个看似无害的查询字符串。通过添加引荐查询字符串,我实际上破坏了我非常喜爱的网站上的一个有效 URL。

    疑虑

    还有一个值得探讨的问题是:HTML 工具是否应该关心引荐查询字符串,毕竟浏览器已经有现成的机制来处理这件事——HTTP Referer 头部,由 Referrer-Policy 控制。该策略可以在服务器层面、文档层面,甚至单个链接上设置。网络标准已经提供了明确的机制来决定应发送多少引荐者信息。而将引荐查询字符串附加到 URL 中,恰恰绕过了这些已有控制。这种做法把隐私和归属问题从引荐机制中剥离出来,反而嵌入到了目标 URL 本身。我认为 HTML 工具不应该这么做。

    此外,还有一个道德层面的问题:以用户的名义修改 URL 来插入引荐查询字符串,这种做法是否正当?我认为不是。

    结论

    最终,我决定从Wander Console中移除引荐查询字符串功能。有人可能会问,为何不干脆将其保留为可选功能?其实,一旦认定该功能存在误导性,我便不再希望它以任何形式存在于我的软件中。该项目仍处于早期阶段,我们仍在发布0.x版本,因此若存在一个合适的时机来移除功能,那就是现在。然而,我持续的研究工作让我无暇顾及此事。直到昨晚,我在阅读器中看到一篇关于禁用查询字符串的文章,这才促使我从学术爱好中抽出一点时间,着手移除这个考虑不周的功能。如今,该功能已被彻底移除。详情参见提交记录b26d77c。最新版本0.6.0已不再包含此功能。

    这将成为我未来所有新爱好项目的重要教训。若将来再次加载URL,我将严格按照网站作者原本的设计意图进行。我绝不会向你的URL中添加任何查询字符串。

    需要完整排版与评论请前往来源站点阅读。