脚本要给仪表盘拉 50 个站点图标,又不想自己托管。一个公开的 favicon API 两行代码就能搞定,但选哪个?DuckDuckGo favicon API 已经悄悄做这活儿多年,和 Google 的 S2 服务以及直接请求 /favicon.ico 一直并存。

三种方案返回的文件格式不同,高并发下的表现也不同,遇到站点没有图标时失败的方式也不同。选错了,缩略图就裂了,日志里还会冒出一堆莫名其妙的 404。

快速对比:DuckDuckGo Favicon API vs 其他方案

对比项DuckDuckGoGoogle S2直接拉 /favicon.ico
接口地址格式icons.duckduckgo.com/ip3/{domain}.icos2.googleusercontent.com/s2/favicons?domain={domain}{site}/favicon.ico
返回格式仅 ICOPNG(默认 16x16)站点返回什么就是什么
默认尺寸多尺寸 ICO 容器16x16(最大 sz=64)站点决定
是否有官方限速文档无官方文档无官方文档取决于站点 CORS / 服务端
CORS 友好是(但有限制)是通常不支持
代理 / 隐私层有(DuckDuckGo 代理)有(Google 代理)无
缺失时的回退返回 404返回默认地球图标404 或 HTML 错误页
最适合的场景浏览器标签页风格图标、需要 ICO小尺寸缩略图、与搜索结果页一致完全原始的源文件

DuckDuckGo Favicon API 到底是怎么工作的

接口非常简单:https://icons.duckduckgo.com/ip3/example.com.ico。DuckDuckGo 在自己的基础设施上抓取站点的真实 favicon,需要时再转成 ICO 容器格式,最后通过他们的 CDN 输出。整个过程完全不会打到源站,因此大部分 CORS 限制都绕过去了。

这种代理方式意味着 URL 本身就充当了一次隐私友好的抓取。访客浏览器不会为了渲染一个小图标就直接去访问目标站点。这跟 Google 的 s2.googleusercontent.com 走的是同一个路子,也解释了为什么这两个端点可以在任意源的 <img> 标签里直接用,无需额外配置 header。

格式上的局限

最大的坑:DuckDuckGo 只返回 ICO 格式。如果你需要一张清晰的 64x64 PNG 用在 iOS 风格的列表里,就得自己再做一次转换。我们的 PNG to ICO 转换指南 讲的是反向操作,但同一套工具两边都能搞定。对于 ICO 就够用的项目——桌面浏览器标签页、老式 <link rel='icon'> 的兜底——DuckDuckGo 确实是最省心的选择。

DuckDuckGo Favicon API 胜出的场景

Google S2 更合适的场景

直接请求 /favicon.ico 仍然合理的场景

对于单一可信来源的站点(你自己的 CDN、合作伙伴站点、已知可靠的数据源),直接拉取 favicon 能拿到原始资源,分辨率还是完整的。SVG、多分辨率 ICO、动图 PNG,原站点实际提供什么你就拿到什么。代价是 CORS:绝大多数站点不会返回浏览器所需的响应头,所以这种方式只能在服务端之间使用,没法在客户端里直接发起请求。

如果你要做批量抓取,没有明确的速率限制文档就是真实的隐患。有的源站请求 50 次之后就给你返回 429,有的则不会。这些公开 API 存在的意义就是把这种风险替你吸收掉。

推荐方案

对于大多数需要在浏览器标签页或列表视图里显示可用图标的客户端项目,如果你需要 ICO,DuckDuckGo favicon API 是不错的默认选择。如果同时需要发布自己的图标,可以搭配我们的 免费 favicon 生成器。如果需要 PNG 缩略图,或者希望达到与 Google 搜索结果一致的显示效果,Google 的 S2 接口更快也更稳定。把直连 /favicon.ico 的方式留给那些可信单一域名、需要拿到完整原始分辨率文件的场景。

无论选哪个 API,结果都要缓存。浏览器的 favicon 请求一旦缓存就极难清除,每次页面加载都去打 DuckDuckGo 的 CDN,迟早让你的服务器吃不消。

核对规范中的要求

HTML 标准把 rel='icon' 定义为表示当前页面的图标的链接关系。