在Chrome扩展中可靠获取网站图标,chrome://favicon?

42

我在我的Google Chrome扩展中使用chrome://favicon/获取RSS订阅源的favicon。我的做法是获取链接页面的基本路径,然后将其附加到chrome://favicon/http://<domainpath>

但这种方法效果不稳定。很多时候它会报告标准的“没有-favicon”图标,即使该页面确实有一个favicon。关于chrome://favicon机制几乎没有任何文档,所以很难理解它的实际工作方式。它只是已经访问过的链接的缓存吗?是否可能检测是否存在图标?

从一些简单的测试来看,它只是你已经访问过的页面的favicon缓存。因此,如果我订阅了dribbble.com的RSS源,它在我的扩展中就不会显示一个favicon。然后,如果我访问chrome://favicon/http://dribbble.com/,它将不会返回正确的图标。然后我在另一个标签中打开dribbble.com,它在标签中显示它的图标,然后当我重新加载chrome://favicon/http://dribbble.com/ 标签时,它将返回正确的favicon。然后我打开我的扩展弹出窗口,它仍然显示标准图标。但如果我重新启动Chrome,它将在所有地方都获取正确的图标。

这只是一些基本的研究,没有让我更接近解决方案。所以我的问题是:对于我正在做的事情,chrome://favicon/是一个正确的用例吗?有文档可以参考吗?它的预期行为是什么?


1
我知道你问这个问题已经有一段时间了。你能分享一下如何获取页面的网站图标吗? - c00000fd
7个回答

24
我也遇到了这个问题,它真的很恼人。
据我所知,Chrome在您访问URL后(省略URL中的#哈希部分)填充chrome://favicon/缓存。它似乎通常会在页面完全加载之后填充此缓存。如果您尝试在相关页面完全加载之前访问chrome://favicon/http://yoururl.com,则通常会返回默认的“地球仪图标”。然后刷新显示图标的页面就可以修复它们。
因此,如果可能的话,在向用户显示图标之前,可能只需刷新显示图标的页面即可作为解决方法。
在我的用例中,我实际上是打开我想要获取favicon的选项卡。到目前为止,我发现获得它们最可靠的方法大致如下:
chrome.webNavigation.onCompleted.addListener(onCompleted);

function onCompleted(details)
{
    if (details.frameId > 0)
    {
        // we don't care about activity occurring within a subframe of a tab
        return;
    }

    chrome.tabs.get(details.tabId, function(tab) {
        var url = tab.url ? tab.url.replace(/#.*$/, '') : ''; // drop #hash
        var favicon;
        var delay;

        if (tab.favIconUrl && tab.favIconUrl != '' 
            && tab.favIconUrl.indexOf('chrome://favicon/') == -1) {
            // favicon appears to be a normal url
            favicon = tab.favIconUrl;
            delay = 0;
        }
        else {
            // couldn't obtain favicon as a normal url, try chrome://favicon/url
            favicon = 'chrome://favicon/' + url;
            delay = 100; // larger values will probably be more reliable
        }

        setTimeout(function() {
            /// set favicon wherever it needs to be set here
            console.log('delay', delay, 'tabId', tab.id, 'favicon', favicon);
        }, delay);
    });
}

这种方法使用 delay=100,在处理新 URL 时正确返回 favicon 的准确率约为 95%。如果您能接受,增加延迟将提高可靠性(对于我的用例,我使用 1500 毫秒,新 URL 仅有不到 1% 的丢失;当同时打开多个标签页时,可靠性会变差)。显然,这是一种相当不精确的方法,但这是我目前找到的最好的方法。
另一个可能的方法是从 http://www.google.com/s2/favicons?domain=somedomain.com 中获取 favicon。我不太喜欢这种方法,因为它需要访问外部网络,依赖于一个没有保证能够正常运行的服务,而且本身也不太可靠;我曾经看到它会不一致地返回 www.domain.com URL 的“地球仪”图标,但对于只有 domain.com 的 URL,则返回正确的图标。
希望这些内容能在某种程度上对您有所帮助。

我之前不知道选项卡的faviconURL属性!不幸的是,我需要一些可以在不打开选项卡的情况下实现的东西。但这很有帮助,我相信我现在可以为未来的用户添加这个功能。我只是希望它不要那么复杂。 - Erik Rothoff
3
我已经提交了一个Chrome缺陷报告,希望能够解决这个问题: https://code.google.com/p/chromium/issues/detail?id=131018 - joelpt
我尝试了这段代码但无法运行。当我调用chrome.webNavigation.onCompleted.addListener(onCompleted)时,出现错误Uncaught TypeError: Cannot read property 'onCompleted' of undefined。在清单中我确实设置了权限"webNavigation"。任何想法为什么chrome.webNavigation似乎未定义? - theMaxx
不太确定为什么会发生这种情况...你是否使用了manifest.json v2?最近一段时间,我没有使用v2样式导致我的扩展程序出现了问题。http://developer.chrome.com/extensions/manifest.html - joelpt

7

截至2020年10月, 看起来使用清单版本3的Chrome扩展程序不再能够访问chrome://favicon/* url。我没有找到消息所提到的“专用API”。

清单v3及更高版本的扩展将无法访问chrome://favicon主机;相反,我们将提供一个专用的API权限和不同的URL。这将导致我们能够加强对chrome:-scheme的权限控制。


2
一些关于Chromium bug跟踪器的见解: Issue 104102: 为访问网站图标创建新的API权限 - Chris McFarland
目前(针对MV3),最佳解决方案似乎是使用Google Favicon Snatcher:https://www.google.com/s2/favicons?domain=www.google.com - Matt B
这个问题的关键是,如果你想失去用户群,你就不能实施这个。 - tmarois
新的API示例:https://dev59.com/4Ggv5IYBdhLWcg3wW_d_#73415941 - previous_developer

6

为了在扩展中使用chrome://favicon/some-site,需要更新manifest.json文件:

"permissions": ["chrome://favicon/"],
"content_security_policy": "img-src chrome://favicon;"

测试版本为 63.0.3239.132(官方构建)(64 位)


谢谢。以下是相关的Chromium更改,允许扩展程序访问网站图标:https://bugs.chromium.org/p/chromium/issues/detail?id=37802 - Ross Allen

6

4

我在Chrome浏览器的历史页面中检查了网站图标,发现了这个更简便的方法。您可以通过以下步骤获取站点图标URL --

favIconURL = "chrome://favicon/size/16@1x/" + tab.url;

别忘了在Chrome中添加“permissions”和“content_security_policy”(https://dev59.com/4Ggv5IYBdhLWcg3wW_d_#48304708)。


3
在最新版本的Chrome中(版本78.0.3904.87(官方版本)(64位)),当测试时,仅添加img-src chrome://favicon;作为content_security_policy仍会显示2个警告消息:

'content_security_policy':CSP指令'script-src'必须被指定(明确地或通过'default-src'隐式地),并且只能列出安全资源。

并且:

'content_security_policy':CSP指令'object-src'必须被指定(明确地或通过'default-src'隐式地),并且只能列出安全资源。

要消除它们,请使用:
"permissions": ["chrome://favicon/"],
"content_security_policy": "script-src 'self'; object-src 'self'; img-src chrome://favicon;"

现在您可以使用chrome://favicon/http://example.com而不会出现任何错误或警告。

1
我尝试了这个解决方案,但没有运气。当我的内容脚本尝试显示某个选项卡的网站图标时,会出现“不允许加载本地资源:chrome://favicon/https://www.google.com”的错误。在Chrome 88.0.4324.146上进行了测试。 - Dmitry Davydov

2
现在有关于获取网站图标的权限的官方文档。

favicon添加到您的权限中

{
  "name": "Favicon API in a popup",
  "manifest_version": 3,
  ...
  "permissions": ["favicon"],
  ...
}

访问网站图标的URL

对于我的简单情况:

const favIconUrl = `chrome-extension://${chrome.runtime.id}/_favicon/?pageUrl=${encodeURIComponent(url)}&size=32`;

从他们的例子中:
function faviconURL(u) {
  const url = new URL(chrome.runtime.getURL("/_favicon/"));
  url.searchParams.set("pageUrl", u);
  url.searchParams.set("size", "32");
  return url.toString();
}

const img = document.createElement('img');
img.src = faviconURL("https://www.google.com") 
document.body.appendChild(img);

这在Chromium Edge上也适用,它会自动将chrome-extension://转换为extension://
注意:在内容脚本中获取网站图标时,必须将"_favicon/*"文件夹声明为可访问的网络资源。例如:
  "web_accessible_resources": [
    {
      "resources": ["_favicon/*"],
      "matches": ["<all_urls>"],
      "extension_ids": ["*"]
    }
  ]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接