Movatterモバイル変換


[0]ホーム

URL:


  1. Mozilla
  2. Add-ons
  3. Browser-Erweiterungen
  4. Inhalts-Skripte

Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten.Erfahre mehr über dieses Experiment.

View in EnglishAlways switch to English

Inhalts-Skripte

Ein Inhalts-Skript ist ein Teil Ihrer Erweiterung, der im Kontext einer Webseite ausgeführt wird. Es kann Seiteninhalte mit den standardmäßigenWeb-APIs lesen und ändern. Das Verhalten von Inhalts-Skripten ähnelt dem von Skripten, die Teil einer Website sind, wie diejenigen, die mithilfe des<script>-Elements geladen werden. Inhalts-Skripte können jedoch nur auf Seiteninhalte zugreifen, wennHost-Berechtigungen für den Ursprung der Webseite gewährt wurden.

Inhalts-Skripte können aufeine kleine Teilmenge der WebExtension-APIs zugreifen, sie können jedochmit Hintergrund-Skripten kommunizieren und dadurch indirekt auf die WebExtension-APIs zugreifen.Hintergrund-Skripte können alleWebExtension-JavaScript-APIs nutzen, haben jedoch keinen direkten Zugriff auf den Inhalt von Webseiten.

Hinweis:Einige Web-APIs sind aufsichere Kontexte beschränkt, was auch für Inhalts-Skripte gilt, die in diesen Kontexten laufen. Ausgenommen hiervon istPointerEvent.getCoalescedEvents(), das in unsicheren Kontexten in Firefox aus Inhalts-Skripten aufgerufen werden kann.

Laden von Inhalts-Skripten

Sie können ein Inhalts-Skript in eine Webseite laden:

  1. Zur Installationszeit, auf Seiten, die URL-Mustern entsprechen.
  2. Zur Laufzeit, auf Seiten, die URL-Mustern entsprechen.
  3. Zur Laufzeit, in bestimmten Tabs.

Es gibt nur einen globalen Geltungsbereichpro Frame, pro Erweiterung. Das bedeutet, dass Variablen aus einem Inhalts-Skript von allen anderen Inhalts-Skripten, unabhängig davon, wie das Inhalts-Skript geladen wurde, zugegriffen werden kann.

Mit den Methoden (1) und (2) können Sie Skripte nur in Seiten laden, deren URLs mit einemÜbereinstimmungsmuster dargestellt werden können.

Mit Methode (3) können Sie auch Skripte in Seiten laden, die mit Ihrer Erweiterung gepackt sind, jedoch nicht in privilegierte Browser-Seiten (wieabout:debugging oderabout:addons).

Hinweis:Dynamische JS-Modulimporte funktionieren jetzt in Inhalts-Skripten. Weitere Details finden Sie inFirefox-Bug 1536094.Es sind nur URLs mit demmoz-extension-Schema erlaubt, was Daten-URLs ausschließt (Firefox-Bug 1587336).

Persistenz

Inhalts-Skripte, die mitscripting.executeScript() oder (nur in Manifest V2)tabs.executeScript() geladen werden, laufen auf Anfrage und sind nicht persistent.

Inhalts-Skripte, die imcontent_scripts-Schlüssel der Manifestdatei oder mit derscripting.registerContentScripts() oder (nur in Manifest V2 in Firefox)contentScripts API definiert sind, sind standardmäßig persistent. Sie bleiben über Browser-Neustarts und Updates sowie Erweiterungs-Neustarts hinweg registriert.

Allerdings bietet diescripting.registerContentScripts() API die Möglichkeit, das Skript als nicht-persistent zu definieren. Dies kann nützlich sein, wenn z. B. Ihre Erweiterung (im Namen eines Benutzers) ein Inhalts-Skript nur in der aktuellen Browser-Sitzung aktivieren möchte.

Berechtigungen, Einschränkungen und Beschränkungen

Berechtigungen

Registrierte Inhalts-Skripte werden nur ausgeführt, wenn der ErweiterungHost-Berechtigungen für die Domäne gewährt wurden.

Um Skripte programmgesteuert einzufügen, benötigt die Erweiterung entweder dieactiveTab-Berechtigung oderHost-Berechtigungen. Diescripting-Berechtigung wird benötigt, um Methoden aus derscripting API zu verwenden.

Bei der Installation kann eine Erweiterung Host-Berechtigungen für Hosts in ihrenmatches-Listen descontent_scripts-Manifest-Schlüssels anfordern. Benutzer können sich nach der Installation der Erweiterung für oder gegen Host-Berechtigungen entscheiden.

Einschränkungen für Domains

SowohlHost-Berechtigungen als auch dieactiveTab-Berechtigung haben Ausnahmen für einige Domains. Inhalts-Skripte sind von der Ausführung auf diesen Domains ausgeschlossen, um den Benutzer beispielsweise davor zu schützen, dass eine Erweiterung ihre Privilegien auf speziellen Seiten erweitert.

In Firefox umfasst dies die folgenden Domains:

  • accounts-static.cdn.mozilla.net
  • accounts.firefox.com
  • addons.cdn.mozilla.net
  • addons.mozilla.org
  • api.accounts.firefox.com
  • content.cdn.mozilla.net
  • discovery.addons.mozilla.org
  • install.mozilla.org
  • oauth.accounts.firefox.com
  • profile.accounts.firefox.com
  • support.mozilla.org
  • sync.services.mozilla.com

Andere Browser haben ähnliche Einschränkungen bezüglich der Websites, von denen Erweiterungen installiert werden können. Beispielsweise ist der Zugriff auf chrome.google.com in Chrome eingeschränkt.

Hinweis:Da diese Einschränkungen addons.mozilla.org umfassen, können Benutzer, die versuchen, Ihre Erweiterung unmittelbar nach der Installation zu verwenden, feststellen, dass sie nicht funktioniert. Um dies zu vermeiden, sollten Sie eine entsprechende Warnung oder eineOnboarding-Seite hinzufügen, um Benutzer vonaddons.mozilla.org wegzubewegen.

Der Satz von Domains kann durch Unternehmensrichtlinien weiter eingeschränkt werden: Firefox erkennt dierestricted_domains-Richtlinie an, wie inExtensionSettings in mozilla/policy-templates dokumentiert. Chromesruntime_blocked_hosts-Richtlinie ist unterExtensionSettings-Richtlinie konfigurieren dokumentiert.

Beschränkungen

Ganze Tabs oder Frames können unter Verwendung vondata:-URI,Blob-Objekten und anderen ähnlichen Techniken geladen werden. Die Unterstützung für die Injektion von Inhalts-Skripten in solchen speziellen Dokumenten variiert zwischen Browsern. Details hierzu finden Sie im FirefoxBug #1411641 Kommentar 41.

Inhalts-Skriptumgebung

DOM-Zugriff

Inhalts-Skripte können auf das DOM der Seite zugreifen und es ändern, genau wie normale Seitenskripte es können. Sie können auch alle Änderungen sehen, die von Seitenskripten am DOM vorgenommen wurden.

Allerdings erhalten Inhalts-Skripte eine "saubere" Ansicht des DOMs. Das bedeutet:

  • Inhalts-Skripte können keine JavaScript-Variablen sehen, die von Seitenskripten definiert wurden.
  • Wenn ein Seitenskript eine eingebaute DOM-Eigenschaft neu definiert, sieht das Inhalts-Skript die Originalversion der Eigenschaft und nicht die neu definierte Version.

Wie in"Content script environment" bei Chrome-Inkompatibilitäten erwähnt, unterscheidet sich das Verhalten zwischen Browsern:

  • In Firefox wird dieses Verhalten alsXray vision bezeichnet.Inhalts-Skripte können auf JavaScript-Objekte aus ihrem eigenen globalen Geltungsbereich oder Xray-verpackte Versionen von der Webseite stoßen.

  • In Chrome wird dieses Verhalten durch eineisolierte Welt erzwungen, die einen fundamentalen anderen Ansatz nutzt.

Betrachten Sie eine Webseite wie diese:

html
<!doctype html><html lang="en-US">  <head>    <meta http-equiv="content-type" content="text/html; charset=utf-8" />  </head>  <body>    <script src="page-scripts/page-script.js"></script>  </body></html>

Das Skriptpage-script.js macht Folgendes:

js
// page-script.js// add a new element to the DOMlet p = document.createElement("p");p.textContent = "This paragraph was added by a page script.";p.setAttribute("id", "page-script-para");document.body.appendChild(p);// define a new property on the windowwindow.foo = "This global variable was added by a page script";// redefine the built-in window.confirm() functionwindow.confirm = () => {  alert("The page script has also redefined 'confirm'");};

Jetzt injiziert eine Erweiterung ein Inhalts-Skript in die Seite:

js
// content-script.js// can access and modify the DOMlet pageScriptPara = document.getElementById("page-script-para");pageScriptPara.style.backgroundColor = "blue";// can't see properties added by page-script.jsconsole.log(window.foo); // undefined// sees the original form of redefined propertieswindow.confirm("Are you sure?"); // calls the original window.confirm()

Das Gleiche gilt umgekehrt; Seitenskripte können keine JavaScript-Eigenschaften sehen, die von Inhalts-Skripten hinzugefügt wurden.

Dies bedeutet, dass Inhalts-Skripte sich darauf verlassen können, dass DOM-Eigenschaften vorhersehbar funktionieren, ohne sich Sorgen machen zu müssen, dass ihre Variablen mit Variablen des Seitenskripts in Konflikt geraten.

Eine praktische Konsequenz dieses Verhaltens ist, dass ein Inhalts-Skript keinen Zugriff auf JavaScript-Bibliotheken hat, die von der Seite geladen werden. Wenn die Seite also beispielsweise jQuery enthält, kann das Inhalts-Skript es nicht sehen.

Wenn ein Inhalts-Skript eine JavaScript-Bibliothek verwenden muss, sollte die Bibliothek selbstneben dem Inhalts-Skript als Inhalts-Skript eingefügt werden:

json
"content_scripts": [  {    "matches": ["*://*.mozilla.org/*"],    "js": ["jquery.js", "content-script.js"]  }]

Hinweis:Firefox bietetcloneInto() undexportFunction(), um es Inhalts-Skripten zu ermöglichen, auf JavaScript-Objekte zuzugreifen, die von Seitenskripten erstellt wurden, und ihre eigenen JavaScript-Objekte an Seitenskripte weiterzugeben.

Weitere Details finden Sie unterObjekte mit Seitenskripten teilen.

WebExtension-APIs

Zusätzlich zu den standardmäßigen DOM-APIs können Inhalts-Skripte diese WebExtension-APIs verwenden:

Vonextension:

Vonruntime:

Voni18n:

Vonmenus:

Alles von:

XHR und Fetch

Inhalts-Skripte können Anfragen mit den normalenwindow.XMLHttpRequest undwindow.fetch() APIs machen.

Hinweis:In Firefox in Manifest V2 erfolgen Inhalts-Skript-Anfragen (z. B. mitfetch()) im Kontext der Erweiterung, daher muss eine absolute URL angegeben werden, um auf Seiteninhalte zu verweisen.

In Chrome und Firefox in Manifest V3 erfolgen diese Anfragen im Kontext der Seite, sodass sie mit einer relativen URL gemacht werden. Zum Beispiel wird/api anhttps://«current page URL»/api gesendet.

Inhalts-Skripte erhalten die gleichen bereichsübergreifenden Berechtigungen wie der Rest der Erweiterung: Wenn die Erweiterung also Zugriff auf einen bestimmten Bereich durch diepermissions Schlüssel inmanifest.json angefordert hat, haben auch ihre Inhalts-Skripte Zugriff auf diesen Bereich.

Hinweis:Beim Verwenden von Manifest V3 können Inhalts-Skripte bereichsübergreifende Anfragen ausführen, wenn der Zielserver sich mittelsCORS dafür entscheidet; jedoch funktionieren Host-Berechtigungen nicht in Inhalts-Skripten, sondern weiterhin auf normalen Erweiterungsseiten.

Dies wird erreicht, indem inhalts-skript-spezifische XHR- und Fetch-Instanzen bereitgestellt werden, die als Nebeneffekt keineOrigin undReferer Headers wie eine Anfrage von der Seite selbst setzen würden; dies ist oft vorzuziehen, um zu verhindern, dass die Anfrage ihre bereichsübergreifende Natur offenbart.

Hinweis:In Firefox in Manifest V2 können Erweiterungen, die Anfragen ausführen, die sich so verhalten sollen, als wären sie vom Inhalt selbst gesendet worden,content.XMLHttpRequest undcontent.fetch() verwenden.

Für browserübergreifende Erweiterungen müssen diese Methoden featurebasiert erkannt werden.

Dies ist in Manifest V3 nicht möglich, dacontent.XMLHttpRequest undcontent.fetch() nicht verfügbar sind.

Hinweis:In Chrome, ab Version 73, und Firefox, ab Version 101 bei Manifest V3, unterliegen Inhalts-Skript-Anfragen der gleichenCORS Politik wie die Seite, in der sie ausgeführt werden. Nur Hintergrundskripte haben erhöhte bereichsübergreifende Berechtigungen. SieheÄnderungen bei bereichsübergreifenden Anfragen in Chrome Extension Content Scripts.

Kommunikation mit Hintergrund-Skripten

Obwohl Inhalts-Skripte nicht direkt die meisten WebExtension-APIs nutzen können, können sie über die Messaging-APIs mit den Hintergrund-Skripten der Erweiterung kommunizieren und somit indirekt auf alle WebExtension-APIs zugreifen, die die Hintergrund-Skripte verwenden können.

Es gibt zwei grundlegende Muster für die Kommunikation zwischen den Hintergrund-Skripten und Inhalts-Skripten:

  • Sie könneneinmalige Nachrichten senden (mit einer optionalen Antwort).
  • Sie können einelängerfristige Verbindung zwischen beiden Seiten einrichten und diese Verbindung nutzen, um Nachrichten auszutauschen.

Einmalige Nachrichten

Um einmalige Nachrichten zu senden, mit optionaler Antwort, können Sie die folgenden APIs verwenden:

Im Inhalts-SkriptIm Hintergrund-Skript
Nachricht sendenbrowser.runtime.sendMessage()browser.tabs.sendMessage()
Nachricht empfangenbrowser.runtime.onMessagebrowser.runtime.onMessage

Zum Beispiel, hier ist ein Inhalts-Skript, das auf Klick-Ereignisse auf der Webseite hört.

Wenn der Klick auf einen Link war, sendet es eine Nachricht an die Hintergrundseite mit der Ziel-URL:

js
// content-script.jswindow.addEventListener("click", notifyExtension);function notifyExtension(e) {  if (e.target.tagName !== "A") {    return;  }  browser.runtime.sendMessage({ url: e.target.href });}

Das Hintergrund-Skript hört auf diese Nachrichten und zeigt eine Benachrichtigung mithilfe dernotifications API an:

js
// background-script.jsbrowser.runtime.onMessage.addListener(notify);function notify(message) {  browser.notifications.create({    type: "basic",    iconUrl: browser.extension.getURL("link.png"),    title: "You clicked a link!",    message: message.url,  });}

(Dieser Beispielcode ist leicht angepasst vomnotify-link-clicks-i18n Beispiel auf GitHub.)

Verbindungsbasierte Nachrichtenübermittlung

Das Senden einmaliger Nachrichten kann mühsam werden, wenn viele Nachrichten zwischen einem Hintergrund-Skript und einem Inhalts-Skript ausgetauscht werden. Ein alternatives Muster ist daher, eine längerlebige Verbindung zwischen den beiden Kontexten aufzubauen und diese Verbindung zu nutzen, um Nachrichten auszutauschen.

Beide Seiten haben einruntime.Port Objekt, das sie nutzen können, um Nachrichten auszutauschen.

Um die Verbindung zu erstellen:

Dies gibt einruntime.Port Objekt zurück.

Sobald jede Seite einen Anschluss hat, können die beiden Seiten:

  • Nachrichten mitruntime.Port.postMessage() senden
  • Nachrichten mitruntime.Port.onMessage() empfangen

Zum Beispiel, sobald es geladen wird, macht das folgende Inhalts-Skript:

  • Verbindet sich mit dem Hintergrund-Skript
  • Speichert denPort in einer VariablenmyPort
  • Hört Nachrichten aufmyPort (und protokolliert sie)
  • VerwendetmyPort, um Nachrichten an das Hintergrund-Skript zu senden, wenn der Benutzer auf das Dokument klickt
js
// content-script.jslet myPort = browser.runtime.connect({ name: "port-from-cs" });myPort.postMessage({ greeting: "hello from content script" });myPort.onMessage.addListener((m) => {  console.log("In content script, received message from background script: ");  console.log(m.greeting);});document.body.addEventListener("click", () => {  myPort.postMessage({ greeting: "they clicked the page!" });});

Das entsprechende Hintergrund-Skript:

  • Hört auf Verbindungversuche vom Inhalts-Skript

  • Bei Empfang eines Verbindungversuchs:

    • Speichert den Port in einer Variablen namensportFromCS
    • Sendet dem Inhalts-Skript eine Nachricht mittels des Ports
    • Beginnt, Nachrichten zu empfangen, die auf dem Port empfangen werden, und protokolliert sie
  • Sendet Nachrichten an das Inhalts-Skript, mitportFromCS, wenn der Benutzer auf die Browser-Aktion der Erweiterung klickt

js
// background-script.jslet portFromCS;function connected(p) {  portFromCS = p;  portFromCS.postMessage({ greeting: "hi there content script!" });  portFromCS.onMessage.addListener((m) => {    portFromCS.postMessage({      greeting: `In background script, received message from content script: ${m.greeting}`,    });  });}browser.runtime.onConnect.addListener(connected);browser.browserAction.onClicked.addListener(() => {  portFromCS.postMessage({ greeting: "they clicked the button!" });});

Mehrere Inhalts-Skripte

Wenn Sie mehrere Inhalts-Skripte gleichzeitig kommunizieren haben, möchten Sie möglicherweise Verbindungen zu ihnen in einem Array speichern.

js
// background-script.jslet ports = [];function connected(p) {  ports[p.sender.tab.id] = p;  // …}browser.runtime.onConnect.addListener(connected);browser.browserAction.onClicked.addListener(() => {  ports.forEach((p) => {    p.postMessage({ greeting: "they clicked the button!" });  });});

Auswahl zwischen einmaligen Nachrichten und verbindungsbasierter Nachrichtenübermittlung

Die Auswahl zwischen einmaligen und verbindungsbasierten Nachrichten hängt davon ab, wie Ihre Erweiterung die Nutzung von Nachrichtenübermittlung plant.

Die empfohlenen Best Practices sind:

  • Verwenden Sie einmalige Nachrichten, wenn...
    • Nur eine Antwort auf eine Nachricht erwartet wird.
    • Eine kleine Anzahl von Skripten hört, um Nachrichten zu empfangen (runtime.onMessage Aufrufe).
  • Verwenden Sie verbindungsbasierte Nachrichtenübermittlung, wenn...
    • Skripte an Sitzungen teilnehmen, in denen mehrere Nachrichten ausgetauscht werden.
    • Die Erweiterung den Fortschritt einer Aufgabe kennen oder wissen möchte, ob eine Aufgabe unterbrochen wird, oder eine Aufgabe, die mit Nachrichtenübermittlung initiiert wurde, unterbrechen möchte.

Kommunikation mit der Webseite

Standardmäßig erhalten Inhalts-Skripte keinen Zugriff auf die von Seitenskripten erstellten Objekte. Sie können jedoch mit Seitenskripten über die DOMwindow.postMessage undwindow.addEventListener APIs kommunizieren.

Zum Beispiel:

js
// page-script.jslet messenger = document.getElementById("from-page-script");messenger.addEventListener("click", messageContentScript);function messageContentScript() {  window.postMessage(    {      direction: "from-page-script",      message: "Message from the page",    },    "*",  );}
js
// content-script.jswindow.addEventListener("message", (event) => {  if (    event.source === window &&    event?.data?.direction === "from-page-script"  ) {    alert(`Content script received message: "${event.data.message}"`);  }});

Für ein vollständiges Arbeitsbeispiel besuchen Sie bitte dieDemo-Seite auf GitHub und befolgen Sie die Anweisungen.

Warnung:Seien Sie sehr vorsichtig, wenn Sie auf unzuverlässige Webinhalte auf diese Weise zugreifen! Erweiterungen sind privilegierter Code, der über leistungsstarke Fähigkeiten verfügen kann, und feindliche Webseiten können sie leicht täuschen, diese Fähigkeiten zu nutzen.

Um ein triviales Beispiel zu geben, nehmen wir an, der Inhalts-Skriptcode, der die Nachricht empfängt, macht so etwas:

js
// content-script.jswindow.addEventListener("message", (event) => {  if (    event.source === window &&    event?.data?.direction === "from-page-script"  ) {    eval(event.data.message);  }});

Jetzt kann das Seitenskript beliebigen Code mit allen Privilegien des Inhalts-Skripts ausführen lassen.

Verwendung voneval() in Inhalts-Skripten

Hinweis:eval() nicht verfügbar in Manifest V3.

In Chrome

eval führt immer Code im Kontext desInhalts-Skripts aus, nicht im Kontext der Seite.

In Firefox

Wenn Sieeval() aufrufen, wird Code im Kontext desInhalts-Skripts ausgeführt.

Wenn Siewindow.eval() aufrufen, wird der Code im Kontext derSeite ausgeführt.

Zum Beispiel, betrachten Sie ein Inhalts-Skript wie dieses:

js
// content-script.jswindow.eval("window.x = 1;");eval("window.y = 2");console.log(`In content script, window.x: ${window.x}`);console.log(`In content script, window.y: ${window.y}`);window.postMessage(  {    message: "check",  },  "*",);

Dieser Code erstellt einige Variablenx undy mitwindow.eval() undeval(), protokolliert ihre Werte und sendet dann eine Nachricht an die Seite.

Beim Empfang der Nachricht protokolliert das Seitenskript die gleichen Variablen:

js
window.addEventListener("message", (event) => {  if (event.source === window && event.data && event.data.message === "check") {    console.log(`In page script, window.x: ${window.x}`);    console.log(`In page script, window.y: ${window.y}`);  }});

In Chrome ergibt dies eine Ausgabe wie diese:

In content script, window.x: 1In content script, window.y: 2In page script, window.x: undefinedIn page script, window.y: undefined

In Firefox ergibt dies eine Ausgabe wie diese:

In content script, window.x: undefinedIn content script, window.y: 2In page script, window.x: 1In page script, window.y: undefined

Das Gleiche gilt fürsetTimeout(),setInterval() undFunction().

Warnung:Seien Sie sehr vorsichtig, wenn Sie Code im Kontext der Seite ausführen!

Die Umgebung der Seite wird von potenziell böswilligen Webseiten kontrolliert, die Objekte, mit denen Sie interagieren, neu definieren können, um sich unerwartet zu verhalten:

js
// page.js definiert console.log neulet original = console.log;console.log = () => {  original(true);};
js
// content-script.js ruft die neu definierte Version aufwindow.eval("console.log(false)");

Help improve MDN

Learn how to contribute Diese Seite wurde automatisch aus dem Englischen übersetzt.

[8]ページ先頭

©2009-2026 Movatter.jp