【问题标题】:How can I detect the current tab's mime type in a Google Chrome extension?如何在 Google Chrome 扩展程序中检测当前选项卡的 MIME 类型?
【发布时间】:2011-06-22 17:06:40
【问题描述】:

我想查看当前选项卡是否是来自背景页面的 PDF 文件。

我可以在最后检查 .pdf 的网址,但有些 PDF 文件没有。

【问题讨论】:

  • 您是否开发过具有此功能的扩展程序?我很想拥有这样的扩展,但不想学习如何为一些个人用途编写代码。

标签: google-chrome google-chrome-extension mime-types mime


【解决方案1】:

您可以在当前选项卡上评估属性document.contentType。 这是browserAction 的示例:

chrome.browserAction.onClicked.addListener(() => {
    chrome.tabs.getSelected((tab) => {
        chrome.tabs.executeScript(tab.id, { code: 'document.contentType' }, ([ mimeType ]) => {
            alert(mimeType);
        });
    })
});

此属性返回文档呈现为的 MIME 类型,而不是 Content-Type 标头(没有关于字符集的信息)。

【讨论】:

    【解决方案2】:

    查看页面内容是一种有点骇人听闻的方法(我不知道它是否总是有效或只是有时有效)。在那里你会找到一个用于 chrome 的 PDF 查看器的元素。它看起来是这样的:

    <embed width="100%" height="100%" name="plugin" src="https://example.com/document.pdf" type="application/pdf">
    

    您可以检查“类型”属性以查看您正在处理的内容。

    【讨论】:

    • 这真的对我有用,非常感谢!这确实有点骇人听闻,但它似乎是唯一适用于“file://” URL 的方法(前提是 manifest.json 声明注入的脚本应该进入与“file://*”选择器匹配的 URL) .这是我在注入脚本中使用的代码:if (document.body.childElementCount === 1) { var embed = document.body.firstElementChild; if (embed.tagName === "EMBED" &amp;&amp; embed.getAttribute("type") === "application/pdf") { /* do something */ } }
    【解决方案3】:

    我不得不在我的一个扩展中做一些类似的事情,并且做了一些与@serg 给出的the answer 非常相似的事情,但使用的是 HEAD 请求。理论上,HEAD 请求应该与 GET 请求相同,但不发送响应正文,对于图像或文件,这可能需要相当多的额外数据和时间等待。

    我还拆分并移动标题以删除可能附加在内容类型上的任何字符集。

    getContentType: function(tab, callback){
        var xhr = new XMLHttpRequest();
        xhr.open("HEAD", tab.url, false);
        xhr.onload =  function(e) {
            if (xhr.readyState === 4) {
                if(xhr.status === 200) {
                    callback(xhr.getResponseHeader("Content-Type").split(";").shift());
                }
                else{
                    callback('Unknown');
                    console.error(xhr.statusText);
                    return;
                }
            }
        };
    
        xhr.onerror = function (e) {
            console.error(xhr.statusText);
            return;
        };
    
        xhr.send();
    }
    

    【讨论】:

      【解决方案4】:

      仅仅为了获取 MIME 类型而发出新请求有点繁重,而且不可靠。例如,如果当前显示的页面是 POST 表单提交的结果,那么发出 GET 请求通常不会导致相同的页面。

      如果您正在开发经常需要访问此信息的扩展程序,请使用chrome.webRequest API 来跟踪响应。以下演示扩展显示了单击浏览器按钮时的内容类型:

      // background.js
      var tabToMimeType = {};
      chrome.webRequest.onHeadersReceived.addListener(function(details) {
          if (details.tabId !== -1) {
              var header = getHeaderFromHeaders(details.responseHeaders, 'content-type');
              // If the header is set, use its value. Otherwise, use undefined.
              tabToMimeType[details.tabId] = header && header.value.split(';', 1)[0];
          }
      }, {
          urls: ['*://*/*'],
          types: ['main_frame']
      }, ['responseHeaders']);
      
      chrome.browserAction.onClicked.addListener(function(tab) {
          alert('Tab with URL ' + tab.url + ' has MIME-type ' + tabToMimeType[tab.id]);
      });
      
      function getHeaderFromHeaders(headers, headerName) {
          for (var i = 0; i < headers.length; ++i) {
              var header = headers[i];
              if (header.name.toLowerCase() === headerName) {
                  return header;
              }
          }
      }
      

      注意事项:

      • 此扩展仅显示在加载扩展后加载的选项卡的结果。
      • 这仅适用于 http/https 页面。 ftp:, file:, filesystem:, blob:, data: 不支持。
      • 当服务器未指定 MIME 类型或 MIME 类型为 text/plain 时,Chrome 将回退到 MIME sniffing,除非设置了 X-Content-Type-Options: nosniff。在第一种情况下,检测到的 MIME 类型可以是任何东西。在后一种情况下,默认 MIME 类型为 text/plain

      为了完整起见,这里有一个manifest.json文件,可以用来测试之前的代码:

      {
          "name": "Click button to see MIME",
          "version": "1",
          "manifest_version": 2,
          "background": {
              "scripts": ["background.js"],
              "persistent": true
          },
          "browser_action": {
              "default_title": "Show MIME"
          },
          "permissions": [
              "webRequest",
              "activeTab",
              "*://*/*"
          ]
      }
      

      【讨论】:

      • 您的回答非常详细且很有帮助。谢谢!
      • 真的很有帮助。这比接受的答案要好得多——实际上不应有任何扩展重新请求标头。
      • 不错的答案,但不幸的是 webRequest 需要设置"persistent": true,这会阻止使用现在首选的事件页面。事件页面的等效 API declarativeWebRequest 仍处于测试阶段,实际上目前似乎完全处于暂停状态。
      【解决方案5】:

      您无法使用当前的 Chrome API afaik 获取它。您可以做的是通过XHR 再次加载此页面并检查返回的内容类型标头。像这样的:

      背景 html:

      chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
          if(changeInfo.status == "loading") {
              if(checkIfUrlHasPdfExtension(tab.url)) {
                  //.pdf
                  pdfDetected(tab);
              } else {
                   var xhr = new XMLHttpRequest();
                   xhr.open("GET", tab.url, true);
                   xhr.onreadystatechange = function() {
                     if (xhr.readyState == 4) {
                       var contentType = xhr.getResponseHeader("Content-Type");
                       if(checkIfContentTypeIsPdf(contentType)) {
                          pdfDetected(tab);
                       }
                     }
                   }
                   xhr.send();
              }
          }
      });
      

      ma​​nifest.json:

      "permissions": [
          "tabs", "http://*/*", "https://*/*"
      ]
      

      对于 PDF 文件,返回的内容类型应为 application/pdf。不过要记住的是,内容类型标头也可以包含编码:text/html; charset=UTF-8

      【讨论】:

      • 谢谢,我相信这会奏效。但恐怕我不会使用它,因为每个页面都会加载两次。
      • @Orny 我同意,我只检查 pdf 扩展名,对于 99% 的情况应该足够了
      • 我正在寻找类似的东西,并且因为我只会在打开扩展弹出窗口时使用它,所以我认为(希望)该请求在大多数情况下都会使用缓存页面。
      • @serg 如何将类型传播到manifest.js 中的content_scripts-文件?
      猜你喜欢
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-27
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      相关资源
      最近更新 更多