Chrome 扩展消息传递:响应未发送

问题描述 投票:0回答:4

我正在尝试在内容脚本和扩展程序之间传递消息

这是我在内容脚本中的内容

chrome.runtime.sendMessage({type: "getUrls"}, function(response) {
  console.log(response)
});

在后台脚本中我有

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.type == "getUrls"){
      getUrls(request, sender, sendResponse)
    }
});

function getUrls(request, sender, sendResponse){
  var resp = sendResponse;
  $.ajax({
    url: "http://localhost:3000/urls",
    method: 'GET',
    success: function(d){
      resp({urls: d})
    }
  });

}

现在,如果我在

getUrls
函数中的 ajax 调用之前发送响应,则响应已成功发送,但是在 ajax 调用的 success 方法中,当我发送响应时,当我进入调试时,它不会发送响应我可以看到
sendResponse
函数的代码中端口为空。

javascript google-chrome google-chrome-extension google-chrome-app
4个回答
380
投票

来自

chrome.runtime.onMessage.addListener
的文档:

如果想异步使用sendResponse(),添加return true;到 onMessage 事件处理程序。

所以你只需要在调用

return true;
后添加
getUrls
来表示你将异步调用响应函数。

请注意,其他文档中没有提到这一点(例如

onMessage
文档),因此开发人员可能会错过这一点。


9
投票

接受的答案是正确的,我只是想添加示例代码来简化这一点。 问题是 API(在我看来)设计得不好,因为它迫使我们开发人员知道是否会异步处理特定消息。如果您处理许多不同的消息,这将成为一项不可能的任务,因为您永远不知道在某些函数的深处,传入的 sendResponse 是否会被称为异步。 考虑一下:

chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) {
if (request.method == "method1") {
    handleMethod1(sendResponse);
}

我如何知道内心深处

handleMethod1
调用是否是异步的?修改
handleMethod1
的人怎么知道它会通过引入异步内容来破坏调用者?

我的解决方案是这样的:

chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) {

    var responseStatus = { bCalled: false };

    function sendResponse(obj) {  //dummy wrapper to deal with exceptions and detect async
        try {
            sendResponseParam(obj);
        } catch (e) {
            //error handling
        }
        responseStatus.bCalled= true;
    }

    if (request.method == "method1") {
        handleMethod1(sendResponse);
    }
    else if (request.method == "method2") {
        handleMethod2(sendResponse);
    }
    ...

    if (!responseStatus.bCalled) { //if its set, the call wasn't async, else it is.
        return true;
    }

});

无论您选择如何处理消息,这都会自动处理返回值。请注意,这假设您永远不会忘记调用响应函数。另请注意,铬可以为我们自动化此操作,我不明白为什么他们不这样做。


2
投票

您可以使用我的库 https://github.com/lawlietmester/webextension 在 Chrome 和 FF 中使用 Firefox 方式实现此功能,无需回调。

您的代码将如下所示:

Browser.runtime.onMessage.addListener( request => new Promise( resolve => {
    if( !request || typeof request !== 'object' || request.type !== "getUrls" ) return;

    $.ajax({
        'url': "http://localhost:3000/urls",
        'method': 'GET'
    }).then( urls => { resolve({ urls }); });
}) );

0
投票

我按照接受的答案将 return true 添加到 onMessage 事件处理程序的末尾。但不幸的是它不起作用。它不再返回未定义的状态。但是 content_script 中收到的返回结果与我在 background.js 上传递给 sendResponse 的对象不同。

它浪费了我 5 个多小时来调试这个问题。

Chrome版本115.0.5790.102是目前最新的。而且我提到的文档也是最新的。问题是没有在异步函数中调用 sendResponse 方法的示例,文档上只有非常模糊的描述。

这是我的例子:

背景.js

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    if (request.greeting === "hello") {
        fetchData(
            "https://api.example.com/"
        )
            .then((res) => {
                console.log(res)  // here the response is json object
                sendResponse(res);
            })
            
    }
    return true;
});

function fetchData(url) {
    return fetch(url, {
        method: "GET",
        cache: "default",
        credentials: "include",
        headers: {
            "Content-Type": "application/json",
        },
        redirect: "follow",
        referrerPolicy: "no-referrer-when-downgrade",
    });
}

content_script.js

    chrome.runtime.sendMessage({greeting: "hello"}, function (response) {
        console.log(response);  //here is another type of object of which the data structure is totally different from what I passed to sendResponse
    })

© www.soinside.com 2019 - 2024. All rights reserved.