Nachricht wurde weitergegeben

Da Inhaltsskripte im Kontext einer Webseite und nicht der Erweiterung ausgeführt werden, benötigen sie oft einige Art der Kommunikation mit dem Rest der Erweiterung. Eine RSS-Reader-Erweiterung könnte beispielsweise um zu erkennen, ob ein RSS-Feed auf einer Seite vorhanden ist, und benachrichtigen dann die um ein Seitenaktionssymbol für diese Seite anzuzeigen.

Die Kommunikation zwischen Erweiterungen und ihren Inhaltsskripten erfolgt per Nachrichtenweitergabe. Beides Nachrichten von der anderen Seite empfangen und auf demselben Kanal antworten können. Eine Nachricht kann ein beliebiges gültiges JSON-Objekt enthalten (null, boolescher Wert, Zahl, String, Array oder Objekt). Es gibt ein einfaches Die API für einmalige Anfragen sowie eine komplexere API für langlebige Anfragen Verbindungen für den Austausch mehrerer Nachrichten mit einem gemeinsamen Kontext. Es ist auch möglich, eine Nachricht an eine andere Erweiterung senden, wenn Sie deren ID kennen, die in der erweiterungsübergreifenden Nachrichten.

Einfache einmalige Anfragen

Wenn Sie nur eine einzelne Nachricht an einen anderen Teil der Erweiterung senden möchten (und optional eine Antwort zurückgegeben), sollten Sie die vereinfachte Version runtime.sendMessage oder tabs.sendMessage verwenden . Damit können Sie einmalig eine JSON-serialisierbare Nachricht von einem Content-Skript an die Erweiterung senden oder umgekehrt. Versa . Mit einem optionalen Callback-Parameter können Sie die Antwort der anderen wenn es eine gibt.

So senden Sie eine Anfrage von einem Inhaltsskript:

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

Das Senden einer Anfrage von der Erweiterung an ein Inhaltsskript sieht sehr ähnlich aus, mit der Ausnahme, dass Sie an welchen Tab sie gesendet werden sollen. In diesem Beispiel wird gezeigt, wie eine Nachricht an das Inhaltsskript gesendet wird. auf dem ausgewählten Tab.

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

Auf der empfangenden Seite müssen Sie einen runtime.onMessage-Event-Listener einrichten, um den angezeigt. Auf der Seite mit Content-Script oder Erweiterung sieht das genauso aus.

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"});
  }
);

Im obigen Beispiel wurde sendResponse synchron aufgerufen. Wenn Sie asynchron verwenden möchten, sendResponse, fügen Sie dem onMessage-Event-Handler return true; hinzu.

Hinweis:Wenn mehrere Seiten onMessage-Ereignisse überwachen, sendet nur die erste Seite, die sendResponse() für ein bestimmtes Ereignis aufruft, die Antwort. Alle anderen Antworten auf dieses Ereignis werden ignoriert.
Hinweis: Der sendResponse-Callback ist nur gültig, wenn er synchron verwendet wird oder wenn der Event-Handler true zurückgibt, um anzugeben, dass er asynchron reagiert. Der Callback der Funktion sendMessage wird automatisch aufgerufen, wenn kein Handler „true“ zurückgibt oder wenn der Callback sendResponse eine automatische Speicherbereinigung aufweist.

Langlebige Verbindungen

Manchmal ist es hilfreich, eine Konversation zu führen, die länger dauert als eine einzelne Anfrage und Antwort. In diesem Fall kannst du einen langlebigen Kanal von deinem Content-Skript zu einer Erweiterungsseite öffnen oder umgekehrt mit runtime.connect bzw. tabs.connect. Der Kanal kann haben optional einen Namen, damit Sie zwischen verschiedenen Verbindungstypen unterscheiden können.

Ein Anwendungsfall wäre eine automatische Formularerweiterung. Das Content-Skript könnte einen Kanal öffnen, Erweiterungsseite für eine bestimmte Anmeldung aufrufen und für jede Eingabe eine Nachricht an die Erweiterung senden. -Element auf der Seite, um die auszufüllenden Formulardaten anzufordern. Über die geteilte Verbindung kann die Erweiterung um die verschiedenen Nachrichten des Content-Skripts bei Bedarf zu verknüpfen.

Beim Herstellen einer Verbindung wird an jedes Ende das Objekt runtime.Port übergeben, das für Nachrichten über diese Verbindung senden und empfangen können.

So öffnest du einen Kanal über ein Content-Skript und sende und empfangst Nachrichten:

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"});
});

Das Senden einer Anfrage von der Erweiterung an ein Inhaltsskript sieht sehr ähnlich aus, mit der Ausnahme, dass Sie den Tab an, mit dem eine Verbindung hergestellt werden soll. Ersetzen Sie im obigen Beispiel einfach den Anruf, um eine Verbindung herzustellen durch tabs.connect.

Zum Verarbeiten eingehender Verbindungen müssen Sie ein runtime.onConnect-Ereignis einrichten. Listener. Dies sieht genauso aus wie bei einem Content-Skript oder einer Erweiterungsseite. Wenn ein anderer Teil Ihres die Erweiterung "connect()" aufruft, wird dieses Ereignis zusammen mit dem runtime.Port-Objekt ausgelöst, das Sie zum Senden und Empfangen von Nachrichten über die Verbindung. So sieht es aus, auf eingehende Verbindungen:

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."});
  });
});

Portlebensdauer

Ports sind als bidirektionale Kommunikationsmethode zwischen verschiedenen Teilen der Erweiterung konzipiert, wobei wird ein Frame (oberste Ebene) als kleinster Teil betrachtet. Beim Aufrufen von tabs.connect, runtime.connect oder runtime.connectNative wird ein Port angezeigt. erstellt wird. Dieser Port kann sofort zum Senden von Nachrichten an das andere Ende verwendet werden über postMessage verwenden.

Wenn sich in einem Tab mehrere Frames befinden, führt der Aufruf von tabs.connect zu mehreren Aufrufen von Das Ereignis runtime.onConnect (einmal für jeden Frame im Tab). Gleichermaßen gilt: runtime.connect verwendet wird, kann das Ereignis "onConnect" mehrmals ausgelöst werden (einmal für jedes Frame im Erweiterungsprozess).

Sie können herausfinden, wann eine Verbindung unterbrochen wird, z. B. wenn Sie separate Status für jeden offenen Port. Dazu können Sie auf das Ereignis runtime.Port.onDisconnect warten. Dieses wird ausgelöst, wenn auf der anderen Seite des Kanals keine gültigen Ports vorhanden sind. Dies geschieht in der Situationen:

  • Es gibt keine Listener für runtime.onConnect am anderen Ende.
  • Der Tab mit dem Port wird entladen, z.B. wenn der Tab aufgerufen wird.
  • Der Frame, aus dem connect aufgerufen wurde, wurde entladen.
  • Alle Frames, die den Port über runtime.onConnect empfangen haben, wurden entladen.
  • runtime.Port.disconnect wird von dem anderen Ende aufgerufen. Wenn ein connect-Aufruf führt, an mehreren Ports am Ende des Empfängers an und disconnect() wird auf einem dieser Ports aufgerufen. Das Ereignis onDisconnect wird nur am Port des Absenders und nicht an den anderen Ports ausgelöst.

Erweiterungsübergreifendes Messaging

Sie können mit der Methode Messaging-API, um mit anderen Erweiterungen zu kommunizieren. So können Sie eine öffentliche API verfügbar machen, die von anderen die Sie nutzen können.

Das Warten auf eingehende Anfragen und Verbindungen ähnelt dem internen Case, mit dem Unterschied, dass Sie die runtime.onMessageExternal oder runtime.onConnectExternal zu verwenden. Hier ist ein Beispiel für jeweils:

// 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.
  });
});

Das Senden einer Nachricht an eine andere Erweiterung ähnelt dem Senden einer Nachricht innerhalb Ihrer Erweiterung. Der einzige Unterschied besteht darin, dass Sie die ID der Erweiterung übergeben müssen, mit der Sie kommunizieren möchten. Beispiel:

// 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(...);

Nachrichten über Webseiten senden

Ähnlich wie bei erweiterungsübergreifenden Nachrichten kann Ihre App oder Erweiterung Nachrichten von regulären Webseiten. Wenn Sie diese Funktion verwenden möchten, müssen Sie zuerst in der Datei „manifest.json“ angeben. mit welchen Websites Sie kommunizieren möchten. Beispiel:

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

Dadurch wird die Messaging-API auf jeder Seite verfügbar, die den von Ihnen angegebenen URL-Mustern entspricht. URL Muster mindestens eine Second-Level-Domain enthalten, also Hostnamenmuster wie "*", "*.com", "*.co.uk" und "*.appspot.com" sind untersagt. Verwenden Sie auf der Webseite die runtime.sendMessage oder runtime.connect API, um eine Nachricht an eine bestimmte App zu senden, oder . Beispiel:

// 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);
  });

In Ihrer App oder Erweiterung können Sie sich Nachrichten von Webseiten über die runtime.onMessageExternal oder runtime.onConnectExternal API, ähnlich wie cross-extension Messaging Nur die Webseite kann eine Verbindung herstellen. Hier ein Beispiel:

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);
  });

Native Werbebotschaften

Erweiterungen und Apps können Nachrichten mit nativen Anwendungen austauschen, die als nativen Messaging-Host. Weitere Informationen zu dieser Funktion finden Sie unter Native Benachrichtigungen.

Sicherheitsaspekte

Inhaltsskripte sind weniger vertrauenswürdig

Content-Skripts sind weniger vertrauenswürdig als die Hintergrundseite der Erweiterung (z. B. eine schädliche Website). -Seite können den Renderer-Prozess gefährden, bei dem die Inhaltsskripte ausgeführt werden. Angenommen, Nachrichten von einem Inhaltsskript wurden möglicherweise von einem Angreifer erstellt. Validieren und alle Eingaben bereinigen. Gehen Sie davon aus, dass an das Content-Skript gesendete Daten an die Webseite gelangen. Umfang der privilegierten Aktionen beschränken, die durch empfangene Nachrichten ausgelöst werden können Skripts erstellt.

Cross-Site-Scripting

Wenn Sie eine Nachricht von einem Inhaltsskript oder einer anderen Erweiterung erhalten, sollten Sie Ihre Skripts mit Bedacht vorgehen nicht zum Opfer von Cross-Site-Scripting werden. Diese Empfehlung gilt für Skripts, die im Hintergrundseite der Erweiterung sowie Content-Skripts, die in anderen Webquellen ausgeführt werden. Vermeiden Sie insbesondere die Verwendung gefährlicher APIs wie die folgenden:

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;
});

Stattdessen sollten Sie sicherere APIs bevorzugen, die keine Skripts ausführen:

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;
});

Beispiele

Einfache Beispiele für die Kommunikation über Nachrichten finden Sie unter examples/api/messaging. -Verzeichnis. Das Beispiel für native Mitteilungen zeigt, wie eine Chrome-App mit einem native App. Weitere Beispiele und Hilfe zum Aufrufen des Quellcodes finden Sie unter Beispiele.