Google chrome extension Chrome扩展消息传递:未选中运行时。lastError:无法建立连接。接收端不存在

Google chrome extension Chrome扩展消息传递:未选中运行时。lastError:无法建立连接。接收端不存在,google-chrome-extension,Google Chrome Extension,我的chrome扩展有以下两个Java脚本: background.js,作为后台脚本运行: chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { if (message.data == "takeScreenshot") { var resp = sendResponse; chrome.tabs.captureVisibleTab(function(

我的chrome扩展有以下两个Java脚本:

background.js
,作为后台脚本运行:

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    if (message.data == "takeScreenshot") {
        var resp = sendResponse;
        chrome.tabs.captureVisibleTab(function(screenshotUrl) {
            resp({
                screenshot: screenshotUrl
            });
        });
        return true; // Return true to tell that the response is sent asynchronously
    } else {
        return "TestReply";
    }
});
api.js
,作为web可访问资源运行:

window.takeScreenshot = (function() {
    var isTakingScreenshot = false; // Semaphore
    return function() {
        if(isTakingScreenshot) return Promise.reject();
        isTakingScreenshot = true;
        return new Promise(function(resolve, reject) {
            chrome.runtime.sendMessage("eomfljlchjpefnempfimgminjnegpjod", "takeScreenshot", function(response) {
                console.log(response);
                isTakingScreenshot = false;
                resolve(response.screenshot);
            });
        });
    }
})()
window.test = (function() {
    return function() {
        return new Promise(function(resolve, reject) {
            chrome.runtime.sendMessage("eomfljlchjpefnempfimgminjnegpjod", "test", function(response) {
                console.log(response);
                resolve(response.length);
            });         
        });
    }
})();
当我在选项卡的控制台中执行任何一个函数(auto complete知道它们,因此它们可用)时,我得到错误:

未选中的runtime.lastError:无法建立连接。接收端不存在

返回的响应是未定义的

我已检查
sendMessage
中的id是否与清单和chrome://extensions 页面,我打开了扩展的后台页面DevTools,并在那里手动添加了相同的侦听器,以确保侦听器确实已注册


我的搜索发现此错误意味着侦听器未正确注册,但我没有找到根本原因。你知道是什么导致了这个错误吗?

好的。我发现了问题所在。我想这是72年以来色度行为的变化。问题是,如果您在后台或弹出页面的另一端打开频道之前尝试调用chrome.runtime.connect(),则会出现该错误

Chrome文档说的是,你可以立即发送消息。在过去,这只会起作用,消息要么被传递,要么被丢弃。但现在它正在失败

:调用tabs.connect、runtime.connect或runtime.connectNative时,将创建一个端口。此端口可立即用于通过postMessage向另一端发送消息

因此,我们的解决方法是确保在调用connect()之前先设置连接侦听器,只需延迟connect()调用:

chrome.runtime.onConnect.addListener(端口=>{
console.log('已连接',端口);
如果(port.name==='hi'){
port.onMessage.addListener(this.processMessage);
}
});
如果您在内容脚本端为断开连接事件设置了侦听器,那么当您尝试chrome.runtime.connect时,它实际上会被调用,而您在另一端没有任何侦听功能。根据法律,哪种行为是正确的

port=chrome.runtime.connect(null,{name:'hi'});
port.onDisconnect.addListener(obj=>{
console.log(“断开连接的端口”);
})
我不知道除了使用setTimeout和尝试在调用chrome.runtime.onConnect.addListener之后获取chrome.runtime.connect之外,是否有其他方法可以避免这种情况。这不是一个好的解决方案,因为它会导致计时错误。也许另一个解决方法是反转通道的方向。并从弹出窗口而不是contentscript启动连接


更新:我为这个问题做了准备。

这里有一个我用来解决这个问题的模式。内容脚本尝试访问背景脚本。如果后台脚本还不可用,那么我们可以从
chrome.runtime.lastError
中看到它被设置(而不是未定义)。在这种情况下,请在1000毫秒后重试

contentScript.js

function ping() {
  chrome.runtime.sendMessage('ping', response => {
    if(chrome.runtime.lastError) {
      setTimeout(ping, 1000);
    } else {
      // Do whatever you want, background script is ready now
    }
  });
}

ping();
chrome.runtime.onConnect.addListener(port => {
  port.onMessage.addListener(msg => {
    // Handle message however you want
  }
);

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => sendResponse('pong'));
backgroundScript.js

function ping() {
  chrome.runtime.sendMessage('ping', response => {
    if(chrome.runtime.lastError) {
      setTimeout(ping, 1000);
    } else {
      // Do whatever you want, background script is ready now
    }
  });
}

ping();
chrome.runtime.onConnect.addListener(port => {
  port.onMessage.addListener(msg => {
    // Handle message however you want
  }
);

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => sendResponse('pong'));

如果在开发Chrome扩展时收到此错误消息,请确保禁用浏览器中安装的其他Chrome扩展。特别是“AdBlock”扩展似乎干扰了消息传递,导致我的扩展抛出此错误。禁用AdBlock为我解决了这个问题。

chrome中的一些安全更改似乎需要在内容脚本和后台脚本之间发送消息时采取稍微不同的方法

要使用的调用是

  • 从背景页:
  • chrome.runtime.onMessageExternal.addListener
    注意 外部零件

  • manifest.json
    需要额外的权限
  • “abcdefghijklmnopqrstuvxyzabcdef”
    是您的扩展id

    ”https://example.com/*“
    是运行内容脚本的域

  • 从内容脚本:

    chrome.runtime.sendMessage
    /
    chrome.runtime.connect
    ,将
    扩展ID
    作为第一个参数

  • 在这里阅读更多

    我之所以在这里添加此项,是因为我有此错误,没有一个StackOverflow帖子解决了我的问题。我的问题是因为我的background.js只访问了一次网页,就向我的内容脚本发送了一堆消息。一旦我添加了一个sender.status检查,它只在选项卡更改“完成”时发送消息,而我的错误消失了

    chrome.tabs.onUpdated.addListener(function(activeInfo, sender, sendResponse) {
        // conditional check prevents sending multiple messages per refresh
        if(sender.status ===  "complete") {
          // do stuff here
        }
    });
    

    在研究了扩展后的解决方案后,我考虑将<>代码>长寿命连接< /代码>改为<代码>简单的一次性请求< /代码>。弹出窗口是用ReactJs制作的。删除所有

    runtime.connect
    runtime.onConnect
    ,更改api并使用
    onMessage
    ,并且只使用
    addListner
    的回调来处理消息后,问题就消失了。我这样做是因为我不需要更多的实时更改,也不需要仅通过请求来更改,想想看,如果您不需要
    长期连接
    请将其更改为
    简单的一次性请求
    。我知道这不是一个解决方案,但对于每个需要加速或完成开发的人来说,这就是我所做的

    我的解决方案:

    // content_script.js
    if (!chrome.runtime.onMessage.hasListeners()) {
      window.chrome.runtime.onMessage.addListener(
        (request, sender, sendResponse) => {
          if (request?.type === 'load_titles') {
            sendResponse({
              type: 'loaded_titles',
              titles,
            });
          }
          if (request?.type === 'anything_else') {
            // do anything else
          }
        },
      );
    }
    
    如果需要在另一个函数中使用sendResponse Asynchronous,则需要在调用
    onMessage.addListner
    时在内部返回true

    负责发送和接收消息的功能:

     // used in app.js on popup
     export function messager(data, callback) {
      window.chrome?.tabs?.query({ url: 'https://example.com/' }, tabs => {
        const tabId = tabs[0].id;
        window.chrome.tabs.sendMessage(tabId, data, callback);
      });
    }
    
    

    由于您使用的是可访问web的资源,因此您必须将其作为无法访问扩展环境的页面脚本运行-您需要通过键公开消息。@wOxxOm您能解释一下