ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

零后端、无数据库:ha.mr如何把链接压缩完全搬进浏览器?

零后端、无数据库:ha.mr如何把链接压缩完全搬进浏览器?

【免费下载链接】ha.mr

Static URL compressor and QR code optimizer

项目地址:https://gitcode.com/gh_mirrors/ha/ha.mr
点击查看免费下载

ha.mr 是一款完全静态的链接压缩(URL 短链接)+ QR 码优化工具:整个压缩和解压逻辑全部写在浏览器里,零后端、无数据库。它没有一条"短代码 → 原始链接"的映射记录,压缩结果就藏在你看到的短链接本身,任何人打开它,浏览器现场解压出原始网址。本文带你快速搞懂它的原理,并用 3 步把它部署成自己的短链接服务。

它和普通短链接服务有什么不同?

传统短链接服务(比如 TinyURL 这类)的工作方式是:你提交长链接 → 服务器生成一个随机码 →把"随机码 → 长链接"写进数据库→ 用户点短码时查库、302 跳转。

ha.mr 彻底反其道而行:

对比项传统短链接服务ha.mr
存储位置数据库URL 本身(#后或路径里)
解压发生地服务器查库用户浏览器本地
跳转方式服务器 302 重定向页面提示"Proceed to …?"手动确认
链接过期/删除可管理不存在(没存过东西)
依赖后端 + 数据库一个静态 HTML 页面
额外能力无一键生成更小的 QR 码

换句话说,ha.mr 的"后端"就是一个 nginx 配置和一张静态页面。这也是它最有趣的地方:链接被压缩成了一段"自解释"的数据。

核心原理:把一个链接压成一个大数字

压缩算法全部集中在 docs/compress.js 这一个文件里(约 660 行),核心思路分三步:

第 1 步:挑掉"人人都能猜到"的部分。协议(http/https)、www.前缀、index.html结尾这些只占 1 个比特的"是/否"标记;端口号直接按数值编码。

第 2 步:用 Huffman 码字典匹配常见网站。这是压缩率的灵魂。docs/compress.js 里内置了四套按真实链接频率排序的 Huffman 码字典——顶级域名、二级域名、域名字符、路径字符,数据来自 Reddit 链接数据集和 url-dataset。效果非常直观:

"com" 的编码就是 "1" —— 1 个比特 "youtube" 是 "001","github" 是 "10100"

第 3 步:剩余部分逐段挑最优编码。路径被拆成一段一段(path / query 参数 / hash),每段先尝试塞进一个"最小字符集"(纯数字?小写?Base64?),不行就退回 Huffman 编码,两种方案比个大小,留短的。

最后,所有比特被合并进一个任意精度的大整数(BigInt),再按输出字符集转成字符串。为什么用大整数而不是定长进制?注释里写得很清楚:一个只有 3 种取值的字段理论上只需约 1.6 bit,二进制会浪费到 2 bit,而共享一个整数流可以做到近乎无损。相关实现在 docs/compress.js。

解压则是完全对称的过程:decompress()把字符串还原成整数,按同样的字典反向走一遍(docs/compress.js)。

没有数据库:payload 到底存在哪?

答案是——就存在链接里,分两种形态(见 docs/main.js):

  • 文字短链接:http://ha.mr#压缩串。#后面的片段标识符按浏览器规范根本不会发送给服务器,服务端连请求都看不到 payload;
  • QR 码:HTTPS://HA.MR/压缩串。扫码后 payload 放在路径里(没有 hash),此时会切换到 QR 专用字母表。

两种情况流程一致:

  1. 你在 docs/404.html 这个页面粘贴长链接,docs/main.js 里的updateOutput()实时压缩,并显示"比原链接小 X%"的绿色/红色提示;
  2. 你把得到的短链接分享出去;
  3. 访问者打开链接,页面自动识别 payload、在本地解压出原始网址,然后弹出一个确认框——"Proceed to <原始链接>?"(docs/main.js),用户点"Yes, redirect me →"才跳转。

手动确认这个看似小气的细节,其实是刻意设计:没有服务器,就没有自动 302 的"信任背书",让用户亲眼看一次目标地址更安心。

部署端只靠一个 nginx 技巧:nginx.conf 里把所有路径都try_files到/404.html——任何 URL 都返回同一张页面,剩下的事全是浏览器 JavaScript 的活。

三种输出字母表:QR 码为什么能更小?

docs/alphabets.js 定义了三个输出字符集:

字母表用途特点
ASCII默认文字输出完整 URL 合法字符集
QR(alphanumeric)QR 码输出大写+数字+$*+-./:,专为 QR 码设计
Emoji文字输出可选用表情组合编码,纯为好玩

QR 码这条路线有讲究:普通 QR 生成器默认按字节模式编码,而 QR 标准里的字母数字模式每 2 个字符只占 11 bit,效率更高。ha.mr 的 QR payload 精确限定在这个模式的字符范围内,并懒加载了轻量级 QR 生成器 docs/lean-qr/lean-qr.js(仅在勾选"Output QR code"时才加载,见 docs/main.js)。生成 QR 时还可以拖动滑条调节最小纠错等级——纠错等级越低,同样内容下的 QR 码越小(docs/404.html)。

页面还会贴心地提醒:如果链接里带着一堆跟踪参数(?和&之后的部分),删掉它们往往比任何压缩算法都有效(docs/404.html)。

一键部署:3 步拥有自己的静态短链接服务

第 1 步:克隆仓库

git clone https://gitcode.com/gh_mirrors/ha/ha.mr

第 2 步:Docker 启动(推荐)

Dockerfile 基于nginx:alpine,只拷贝静态文件;compose.yml 把容器 80 端口映射到宿主 8080:

docker compose up -d # 浏览器打开 http://localhost:8080 即可

第 3 步(可选):装一个命令行版hamr

项目附带 Nix 包定义(flake.nix、package.nix),能装出一个名为hamr的 CLI,本质是用 Node 跑 standalone.js:

nix run .#hamr -- "https://www.example.com/index.html" # 压缩 nix run .#hamr -- "https://www.example.com/index.html" qr # 生成 QR 版短链 nix run .#hamr -- "http://ha.mr#xxxx" decode # 把短链解回原址

没有 Nix 也没关系——核心就是两个文件,把 docs/compress.js 和 docs/alphabets.js 拷进任何能跑 ES Module 的 Node 环境即可。

诚实的边界:它不是什么

  • 只支持 http/https,且明确拒绝 URL 里带账号密码(docs/main.js);
  • 短链接可能比长链接还长:字典是统计产物,一个生僻小站的链接压缩后反而更大,页面会用红色如实标出"Output is X% larger",不藏着掖着;
  • 无法删除、无过期、无统计:既然没存东西,就什么管理功能都没有。作者在 README 里明确写着"Keep the scope small"——这是一个刻意保持极简的项目,欢迎修 bug,但谢绝功能堆叠(README.md)。
适合你,如果…不适合你,如果…
想要一个能自己托管、永远不需要运维的短链接页需要删除链接、统计点击量
经常给实体物料印 QR 码,希望码更小需要非 http(s) 协议(ftp、git 等)
想学习"链接也能被信息论压缩"的完整实现期望随机码不可预测(payload 完全可逆)

写在最后

ha.mr 用最少的代码演示了一个反直觉的事实:"缩短链接"本质是编码问题,不是数据库问题。一个静态页面 + 两套 Huffman 字典 + 一个浏览器 JS 文件,就完成了传统服务要后端才能做的事,还顺手把 QR 码做得更紧凑。代码量小到可以一个下午读完——从 docs/compress.js 入手,你会发现"大整数当数据流"这个设计比想象中优雅得多。

【免费下载链接】ha.mr

Static URL compressor and QR code optimizer

项目地址:https://gitcode.com/gh_mirrors/ha/ha.mr
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进