Skip to content

架构设计

本文用图解方式说明 IconHash Skills 的整体架构、分层职责与数据流。

5 层架构 单向无环依赖 700+ 指纹

阅读建议

如果你是第一次接触本项目,建议按顺序通读各小节;如果只关心某条命令的内部实现,可直接跳到 核心数据流:identify 命令。需要快速理解模块边界时,先看 整体分层 的 flowchart。

整体分层

IconHash Skills 采用清晰的 5 层架构,从用户入口到外部接口逐层下沉:

层级名称职责关键组件
入口层接收用户/外部请求CLI、HTTP API、MCP、GUI
命令层解析参数、编排子命令cmd/*.go
核心包哈希、匹配、协议、资源pkg/hasherpkg/fingerprint
基础设施通用能力MurmurHash3、HTTP 客户端、embed
外部接口真实世界对接目标网站、搜索引擎、AI 代理
各层职责详解
  • 入口层:不处理业务逻辑,只负责把请求翻译成统一的命令调用,确保 CLI / API / MCP / GUI 四条入口路径行为一致。
  • 命令层:使用 cobra 的子命令模式,每个子命令只编排「发现 → 哈希 → 匹配 → 格式化」这条主线,不直接实现算法。
  • 核心包:所有业务逻辑下沉到此层,pkg/* 之间保持单向依赖,便于独立单测。
  • 基础设施:提供与具体业务无关的通用能力,例如 MurmurHash3 的封装、embed.FS 嵌入指纹库等。
  • 外部接口:仅在最外层被引用,核心包通过接口抽象与之交互,方便在测试中替换为 mock。

包依赖关系

核心代码包之间的依赖方向(单向无环):

依赖始终从上层指向下层,pkg/* 之间不产生循环依赖,便于独立测试与复用。

依赖红线

新增任何 pkg/* 之间的依赖时,必须保证不形成环。pkg/hasherpkg/fingerprint 共同依赖 pkg/util,但 util 绝不反向引用上层包——这是项目可测试性的根基。

核心数据流:identify 命令

iconhash identify <url> 是最典型的端到端流程,融合了发现、哈希、匹配三个阶段:

端到端 发现→哈希→匹配

三阶段解耦的价值

discoverhashlookup 三步被刻意拆分到不同的 pkg/* 中,而非塞进一个长函数。这样 pkg/hasher 可以脱离网络独立测试,pkg/fingerprint 可以用静态哈希值做匹配回归,而 discover 的探测策略也能单独演进(例如未来支持 SVG 站点图标)。

为什么会对每个图标都查一次指纹库?

站点可能同时声明多个 <link rel="icon">(不同尺寸/格式)。逐图标哈希 + 查询可以覆盖所有候选,避免遗漏真实身份。最终结果会去重合并,用户拿到的就是该站点所有可识别图标对应的指纹集合。

哈希计算细节

MMH3 哈希的计算步骤与历史渊源——这是 Shodan/Fofa 等搜索引擎沿用的事实标准:

事实标准 int32 Base64 前置

为什么先 Base64? 沿用早期 Python 实现的惯例,Shodan 等引擎索引也基于此约定——保持一致才能与现有搜索结果互通。

哈希值符号陷阱

默认输出是 带符号 int32,因此可能出现负数(例如 -1161367058)。这是 MurmurHash3 取低 32 位后的有符号表示,并非错误。若你的下游系统要求无符号值,请使用 --uint32 输出(对应 3133600238),二者互为补码关系。

图标发现策略

发现器按优先级顺序探测网站上的所有图标:

多源探测 自动去重

探测顺序背后的考量

顺序是 link 标签 → apple-touch-icon → /favicon.ico,因为前者的图标通常更能代表站点真实身份(自定义 logo),而 /favicon.ico 作为兜底往往只是默认占位图。优先识别自定义图标能提高指纹命中率。

当三个来源都没有图标时

/favicon.ico 返回非 200(如 404)会被判定为无图标,发现器返回空列表。此时 identify 不会报错,而是输出空结果——这是有意设计,避免因单个站点缺少图标而中断批量扫描。

Lite vs Full 构建变体

两种构建变体在指纹库加载方式上不同,影响二进制体积与离线能力:

Lite 默认 Full 离线 embed_fingerprints tag
特性LiteFull
二进制体积~5 MB~8 MB
首次需联网是(自动下载)
离线可用否(首次后是)
指纹更新自动拉取最新需重新编译
适用场景日常使用、Docker离线环境、内网

如何选择?

  • 日常开发、CI、Docker 镜像 → 用默认 Lite,体积小、指纹永远最新。
  • 内网 / 离线 / 安全合规环境 → 编译时加 -tags embed_fingerprints 生成 Full,启动即用、不依赖外网。

Lite 首次联网的注意点

Lite 首次查询指纹时会从 GitHub 拉取 fingerprints.json 并缓存到本地。若运行环境无法访问 GitHub(如受限网络),首次查询会失败——此时要么切换到 Full 构建,要么提前手动放置缓存文件。详见 构建与发布

API 服务器请求生命周期

HTTP API 服务器处理一个请求的完整路径:

中间件链 认证网关 统一 JSON 响应

公开端点 vs 受保护端点

认证中间件按路由白名单放行:健康检查、文档等公开端点无需鉴权直接通过;而 /hash/*/lookup/*受保护端点必须携带有效的 Authorizationtoken。这样既方便探活,又不暴露核心能力。

401 与 200 之外的返回码
  • 400 Bad Request:参数缺失或 URL 格式非法。
  • 429 Too Many Requests:触发限流(若启用)。
  • 502 Bad Gateway:下载目标图标失败(上游站点不可达或超时)。
  • 500 Internal Server Error:哈希/匹配阶段出现非预期异常,会带 error_id 便于排查。

目录结构

各核心包一句话职责
职责
pkg/hasher下载图标、Base64 编码、MurmurHash3 计算
pkg/fingerprint指纹库加载与哈希反查
pkg/apiHTTP 路由、中间件、端点处理器
pkg/mcpMCP 协议封装与工具暴露
pkg/gui内嵌 GUI 静态资源(embed.FS
pkg/util搜索语法格式化等纯函数工具
pkg/version版本号注入与查询

详细目录说明见 构建与发布


速记口诀

入口多、命令薄、核心厚、基础稳、外部远。——记住这五个词,就记住了 IconHash Skills 的分层骨架。

下一篇:集成方式 — 4 种集成路径如何选择。

基于 MIT 许可证发布