訊息傳遞

由於內容指令碼是在網頁環境中執行,而不是擴充功能,因此通常需要一些程式碼。 可讓您與擴充功能的其他部分通訊舉例來說,RSS 閱讀器擴充功能可能會使用 內容指令碼,偵測網頁上是否有 RSS 動態消息,然後通知背景網頁 即可顯示該網頁的網頁動作圖示。

擴充功能及其內容指令碼之間的通訊方式,是透過訊息傳送功能運作。兩者皆可 對方可以聆聽對方傳送的訊息,並在同一管道回覆。訊息可以 包含任何有效的 JSON 物件 (空值、布林值、數字、字串、陣列或物件)。做法很簡單 適用於一次性要求的 API 和更複雜的 API,可讓您使用長效型 API 連線,透過共用情境交換多則訊息。您也可以 如果您知道這個擴充功能的 ID,請參閱跨擴充功能 訊息」一節。

簡單的一次性要求

如果您只需要將一則訊息傳送至擴充功能的其他部分 (並且視需要 回應),您應使用簡化的 runtime.sendMessagetabs.sendMessage。 這可讓您從內容指令碼將一次性的 JSON 序列化訊息傳送至擴充功能 (或從延伸) 。可選用的回呼參數可讓您處理來自 如果有的話。

從內容指令碼傳送要求看起來會像這樣:

chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});

從擴充功能傳送要求到內容指令碼看起來非常相似,但您必須 指定要傳送至哪個分頁。這個範例示範如何傳送訊息至內容指令碼 就在所選分頁中

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
    console.log(response.farewell);
  });
});

在接收端,您需要設定 runtime.onMessage 事件監聽器來處理 撰寫新的電子郵件訊息這和內容指令碼或擴充功能網頁看起來相同。

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting == "hello")
      sendResponse({farewell: "goodbye"});
  }
);

在上述範例中,系統已同步呼叫 sendResponse。如果想以非同步方式 sendResponse,將 return true; 新增至 onMessage 事件處理常式。

注意:如果多個頁面正在監聽 onMessage 事件,則只有第一個針對特定事件呼叫 sendResponse() 能夠成功傳送回應。系統會忽略對該事件的所有其他回應。
注意:只有在同步使用,或事件處理常式傳回 true 表示將以非同步方式回應時,sendResponse 回呼才有效。如果沒有處理常式傳回 true,或者 sendResponse 回呼是垃圾收集,則系統會自動叫用 sendMessage 函式的回呼。

長期連線

聊天室的持續時間比單一要求和回應長,有時候有幫助。 在這個情況下,您可以從內容指令碼開啟一個長效頻道,然後開啟擴充功能頁面 或分別使用 runtime.connecttabs.connect。管道可以 選擇性名稱,方便您區分不同類型的連線。

其中一個用途可能是自動填寫表單額外資訊。內容指令碼可以開啟頻道 取得特定登入資訊的擴充功能頁面,並針對每個輸入內容將訊息傳送至擴充功能 元素,要求表單資料填寫。共用連線可讓擴充功能 保持共用狀態連結內容指令碼中的數則訊息。

建立連線時,每個端點都會獲得一個 runtime.Port 物件,用於 透過該連線收發訊息

以下說明如何透過內容指令碼開啟頻道,以及傳送及監聽訊息:

var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question == "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question == "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});

從擴充功能傳送要求到內容指令碼看起來非常相似,但您必須 指定要連結的分頁。只要將上述呼叫取代為 tabs.connect.

為了處理連入連線,您必須設定 runtime.onConnect 事件 接聽程式。這在內容指令碼或擴充功能網頁中看起來相同。如果網站的其他部分 擴充功能呼叫「connect()」、引發此事件,以及您可以下載的 runtime.Port 物件 用於透過該連線收發訊息。以下是回應內容 連入連線:

chrome.runtime.onConnect.addListener(function(port) {
  console.assert(port.name == "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke == "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer == "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer == "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});

通訊埠生命週期

連接埠是專用於擴充功能各部分之間的雙向通訊方式, 畫面最小化成一個 (頂層) 頁框。 呼叫 tabs.connectruntime.connectruntime.connectNativePort 時 即可透過這個通訊埠,立即透過該通訊埠傳送訊息至另一端, postMessage

如果分頁中有多個影格,呼叫 tabs.connect 即可多次叫用 runtime.onConnect 事件 (分頁中每個影格一次)。同樣地, 如果使用 runtime.connect,可能會多次觸發 onConnect 事件 (每 擷取頁框)。

您可能會想瞭解連線關閉的時間,例如為了維護 狀態。為此,您可以監聽 runtime.Port.onDisconnect 事件。這個 事件就會引發事件。這會發生在 下列情況:

  • 另一端沒有 runtime.onConnect 的事件監聽器。
  • 含有通訊埠的分頁已卸載 (例如,分頁是否正在瀏覽)。
  • 呼叫 connect 的影格已卸載。
  • 所有接收通訊埠 (透過 runtime.onConnect) 的影格均已卸載。
  • 另一端呼叫 runtime.Port.disconnect。請注意,如果 connect 呼叫結果 且該通訊埠在其中一個通訊埠上呼叫 disconnect(),然後 onDisconnect 事件只會在傳送者的通訊埠上觸發,在其他通訊埠上則不會。

跨額外資訊訊息功能

除了在擴充功能中的不同元件之間傳送訊息之外,您還可以使用 訊息 API,以便與其他擴充功能通訊。這樣您就能向其他使用者公開 也能使用額外資訊

監聽傳入的要求和連線與內部案例類似,差別在於可以使用 runtime.onMessageExternalruntime.onConnectExternal 方法。這裡舉例說明 每個:

// For simple requests:
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id == blocklistedExtension)
      return;  // don't allow this extension access
    else if (request.getTargetData)
      sendResponse({targetData: targetData});
    else if (request.activateLasers) {
      var success = activateLasers();
      sendResponse({activateLasers: success});
    }
  });

// For long-lived connections:
chrome.runtime.onConnectExternal.addListener(function(port) {
  port.onMessage.addListener(function(msg) {
    // See other examples for sample onMessage handlers.
  });
});

同樣地,傳送訊息到其他擴充功能就如同在您的額外資訊中傳送。 唯一的差別在於,您必須傳遞要通訊的擴充功能 ID。例如:

// The ID of the extension we want to talk to.
var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
  function(response) {
    if (targetInRange(response.targetData))
      chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
  }
);

// Start a long-running conversation:
var port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);

從網頁傳送訊息

如同跨擴充功能傳訊,您的應用程式或擴充功能可以接收及回覆 。如要使用這項功能,您必須先在 manifest.json 中指定 可讓您進行通訊的網站。例如:

"externally_connectable": {
  "matches": ["*://*.example.com/*"]
}

如此一來,凡是與指定網址模式相符的網頁,都能看到訊息 API。網址 模式至少須包含一個第二層網域,也就是主機名稱模式,例如「*」、「 「*.com」、「*.co.uk」和「*.appspot.com」。只要在網頁上使用 runtime.sendMessageruntime.connect API 可讓您傳送訊息至特定應用程式或 。例如:

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
      handleError(url);
  });

你可以透過應用程式或擴充功能,聆聽來自網頁的訊息 runtime.onMessageExternalruntime.onConnectExternalAPI,與 跨擴充功能類似 訊息只有網頁可以啟動連線。範例如下:

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.url == blocklistedWebsite)
      return;  // don't allow this web page access
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });

內建訊息傳遞功能

凡是已註冊註冊為裝置的原生應用程式,都可以交換訊息和應用程式 內建訊息傳遞主機。如要進一步瞭解這項功能,請參閱原生訊息傳遞

安全性考量

內容指令碼較不可靠

內容指令碼不可靠,比擴充功能背景網頁更可靠 (例如惡意網路) 網頁可能會破壞內容指令碼執行的轉譯器程序)。假設 內容指令碼中的訊息可能是由攻擊者製作,因此請務必驗證並驗證 處理所有輸入內容。假設傳送到內容指令碼的任何資料都可能流向網頁。 限制內容從內容收到的訊息可觸發的權限動作範圍 指令碼

跨網站指令碼攻擊

收到內容指令碼或其他擴充功能傳來的訊息時,請務必謹慎處理指令碼 不會因此落於跨網站指令碼攻擊的情況下遭受受害者。這項建議適用於 擴充功能背景頁面以及在其他網路來源內執行的內容指令碼。 具體來說,請避免使用危險的 API,例如下列 API:

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be evaluating an evil script!
  var resp = eval("(" + response.farewell + ")");
});
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be injecting a malicious script!
  document.getElementById("resp").innerHTML = response.farewell;
});

請改為使用不會執行指令碼的更安全的 API:

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // JSON.parse does not evaluate the attacker's scripts.
  var resp = JSON.parse(response.farewell);
});
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // innerText does not let the attacker inject HTML elements.
  document.getElementById("resp").innerText = response.farewell;
});

範例

您可以在 examples/api/訊息 aging 中找到透過訊息溝通的簡單範例。 目錄。內建訊息功能範例示範 Chrome 應用程式如何與 原生應用程式如需更多範例及瞭解如何查看原始碼,請參閱範例