Arbeiten mit documentId
Eine documentId ist eine UUID-Zeichenfolge, die ein einzigartiges Dokument identifiziert, das in einem Tab oder Frame geladen ist. Dieser Leitfaden erklärt, was documentId ist, warum es nützlich ist und wie es in den WebExtension-APIs verwendet wird.
Tabs, Frames und Dokumente
Ein Browser-Tab, identifiziert durch eine tabId, ist der oberste Container für Webinhalte. Innerhalb eines Tabs können Inhalte in mehrere Frames strukturiert werden: der Hauptframe (äußerster), der eine frameId von 0 hat, und alle verschachtelten <iframe>-Elemente, die jeweils eine frameId haben. Da die oberste frameId 0 ist, kann frameId nicht verwendet werden, um alle Frames über alle Tabs hinweg eindeutig zu identifizieren.
Jeder Frame enthält ein Dokument, die HTML-Seite, die unter einer URL geladen wird. Die Beziehung zwischen diesen drei Konzepten ist:
- Ein Tab enthält ein oder mehrere Frames.
- Ein Frame enthält ein Dokument.
- Wenn ein Frame zu einer neuen URL navigiert, wird sein Dokument ersetzt, aber der gleiche Frame und somit die gleiche
frameIdbleibt bestehen.
Das bedeutet, dass die Kombination aus tabId und frameId einen Frame (einen stabilen Browsing-Kontext) identifiziert, aber nicht das darin geladene Dokument.
Dokumente und Frames sind auch in Nicht-Tab-Kontexten vorhanden, einschließlich, aber nicht beschränkt auf:
Operationen mit Tab- und Frame-IDs
Viele WebExtension-APIs verwenden tabId und frameId, um zu identifizieren, wo eine Operation ausgeführt werden soll:
- Skript- und CSS-Injektion:
scripting.executeScript(),scripting.insertCSS(), undscripting.removeCSS()akzeptieren einetabIdund optionaleframeIdsin ihremscripting.InjectionTarget, um anzugeben, wo injiziert werden soll. - Benutzerskript-Injektion:
userScripts.execute()nimmttabIdundframeIdsin seinemtarget. - Messaging:
tabs.sendMessage()undtabs.connect()akzeptieren einetabIdund eine optionaleframeId, um eine Nachricht an ihren Empfänger zu senden. - Frame-Informationen:
webNavigation.getFrame()undwebNavigation.getAllFrames()verwendentabIdundframeId, um Frame-Details zu suchen oder aufzulisten. - Ereignisse: Navigationsevents (
webNavigation.onCommitted,webNavigation.onCompletedund andere), Anfrageereignisse (webRequest.onBeforeRequestund andere), undproxy.onRequestbeinhalten alletabIdundframeId, um zu identifizieren, wo ein Event aufgetreten ist.
Da frameId den Frame anstelle seines Inhalts identifiziert, besteht ein potenzielles Race-Condition-Risiko. Nachdem Ihre Erweiterung die tabId und frameId erhalten hat, kann sich das geladene Dokument ändern, sodass die nachfolgende Operation der Erweiterung nicht mehr das beabsichtigte Dokument anvisiert. documentId wurde eingeführt, um dieses Problem zu lösen.
Was ist eine documentId?
Eine documentId wird jedem Dokument zugewiesen, wenn es geladen wird, und bleibt über die gesamte Lebensdauer des Dokuments konstant. Wenn ein Frame zu einer neuen URL navigiert, behält er seine frameId, erhält aber eine neue documentId. Dies unterscheidet documentId von frameId: Eine frameId identifiziert den Browsing-Kontext (das Frame-Element selbst), während eine documentId das geladene Dokument innerhalb dieses Kontexts identifiziert.
Die documentId behandelt korrekt Sonderfälle, die frameId nicht unterscheiden kann:
- Navigationen: Jeder neue Dokumenten-Ladevorgang, einschließlich Cross-Origin-Navigationen, erhält eine neue
documentId, obwohl dieframeIdunverändert bleibt. - Reloads: Ein Neuladen der Seite erzeugt eine neue
documentId, was auf ein frisches Dokument hinweist. history.pushState()und Fragment-Updates: Diese erzeugen kein neues Dokument, sodass diedocumentIdunverändert bleibt.
Da sich die ID bei jedem Dokumenten-Ladevorgang ändert, bleibt die von Ihrer Erweiterung für ein Dokument erhaltene ID nur für dieses Dokument gültig. Wenn der Frame navigiert ist, passt die documentId nicht mehr. Wenn Ihre Erweiterung ein Skript injiziert oder eine Nachricht mit der dokumentierten ID nach der Navigation sendet, schlägt die Operation fehl, anstatt stillschweigend das falsche Dokument zu adressieren.
Wenn ein Dokument aus dem Vorwärts-/Rückwärtscache (bfcache) wiederhergestellt wird, wird auch seine ursprüngliche documentId wiederhergestellt.
Wie erhält man eine documentId?
Es gibt mehrere Möglichkeiten, eine documentId zu erhalten:
- Rufen Sie
runtime.getDocumentId()mit einemwindowoder Frame-Element innerhalb eines Inhaltsskripts auf. - Lesen Sie die
documentIdoderparentDocumentId-Eigenschaft in den Ergebnissen vonwebNavigation.getFrame()oderwebNavigation.getAllFrames(). - Lesen Sie die
documentIdoderparentDocumentIdvon Ereignisdetails inwebNavigation-Ereignissen (für Ereignisse, bei denen das Dokument des Navigationziels bekannt ist, wenn das Ereignis ausgelöst wird). - Lesen Sie die
documentIdaus Ereignisdetails vonwebRequest-Ereignissen. - Lesen Sie die
documentIdausruntime.MessageSender, wenn Sie Nachrichten mitruntime.onMessage,runtime.onConnectund verwandten Listenern empfangen. - Lesen Sie die
documentIdaus den Ergebnissen vonruntime.getContexts().
Verwendung von documentId zur Zieladresse von Dokumenten
Wenn Sie eine documentId haben, können Sie diese verwenden, um dieses Dokument anzusteuern:
- Skript- und CSS-Injektion: Verwenden Sie
documentIdsinscripting.InjectionTargetmitscripting.executeScript(),scripting.insertCSS()undscripting.removeCSS(), um in spezifische Dokumente zu injizieren. - Benutzerskript-Injektion: Setzen Sie
documentIdsimtarget-Parameter vonuserScripts.execute(). - Messaging: Übergeben Sie
documentIdimoptions-Parameter vontabs.connect()odertabs.sendMessage(), um an ein Dokument in einem Tab zu senden. - Frame-Suche: Übergeben Sie
documentIdanwebNavigation.getFrame()als Alternative zutabIdundframeId. Wenn Sie auchtabIdundframeIdangeben, wird der Frame nur zurückgegeben, wenn alle drei übereinstimmen.
APIs, die documentId unterstützen
Diese APIs unterstützen documentId.
Abrufen einer documentId
runtime.getDocumentId()gibt die Dokument-UUID eines Zielsfensters oder Frame-Elements zurück.
documentId in Rückgabewerten und Ereignisdetails
runtime.getContexts()gibt einedocumentIdfür jeden Erweiterungskontext zurück und unterstützt einedocumentIds-Filtereigenschaft.runtime.MessageSenderenthältdocumentId, verfügbar inruntime.onConnect,runtime.onMessage,runtime.onMessageExternal,runtime.onConnectExternal,runtime.onUserScriptMessageundruntime.onUserScriptConnect-Listenern.scripting.executeScript()gibtdocumentIdin jedemInjectionResultzurück.userScripts.execute()-Ergebnisse enthaltendocumentId.webNavigation.getAllFrames()gibtdocumentIdundparentDocumentIdfür jeden Frame zurück.webNavigation.getFrame()gibtdocumentIdundparentDocumentIdzurück.webNavigation.onCommitted,webNavigation.onDOMContentLoaded,webNavigation.onCompleted,webNavigation.onErrorOccurred,webNavigation.onReferenceFragmentUpdatedundwebNavigation.onHistoryStateUpdatedbeinhaltendocumentIdundparentDocumentIdin den Ereignisdetails.webNavigation.onBeforeNavigatekann eineparentDocumentIdhaben, wenn ein Frame navigiert, aber keinedocumentId, da das Ereignis ausgelöst wird, bevor ein Dokument geladen wird.- Alle
webRequest-Ereignisse —webRequest.onBeforeRequest,webRequest.onBeforeSendHeaders,webRequest.onSendHeaders,webRequest.onHeadersReceived,webRequest.onAuthRequired,webRequest.onBeforeRedirect,webRequest.onResponseStarted,webRequest.onCompletedundwebRequest.onErrorOccurred— beinhaltendocumentIdundparentDocumentId, wenn zutreffend. proxy.RequestDetailsbeinhaltetdocumentIdundparentDocumentId, wenn zutreffend.declarativeNetRequest.onRuleMatchedDebugbeinhaltetdocumentId, wenn zutreffend.
documentId für Zielanwendungen
scripting.InjectionTargetunterstütztdocumentIds, um spezifische Dokumente inscripting.executeScript(),scripting.insertCSS()undscripting.removeCSS()anzusteuern.userScripts.execute()targetunterstütztdocumentIds.tabs.connect()optionsunterstütztdocumentId, um ein spezifisches Dokument anzusteuern.tabs.sendMessage()optionsunterstütztdocumentId, um ein spezifisches Dokument anzusteuern.webNavigation.getFrame()akzeptiertdocumentIdals Alternative zutabIdundframeId.
Zukünftige Entwicklungen
Die WebExtensions Community Group (WECG) diskutiert die Möglichkeit, die Anforderung zu lockern, tabId zusammen mit documentId beim Ansteuern von Dokumenten bereitzustellen. Siehe WECG issue #91 für die Diskussion.