Come posso caricare un web worker condiviso con uno script utente?

Voglio caricare un lavoratore condiviso con uno script utente. Il problema è che lo script utente è gratuito e non ha un modello di business per l’hosting di un file, né vorrei usare un server, anche gratuito, per ospitare un file minuscolo. Indipendentemente da ciò, l’ ho provato e ho (ovviamente) ottenuto lo stesso errore di politica di origine:

Uncaught SecurityError: Failed to construct 'SharedWorker': Script at 'https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js' cannot be accessed from origin 'http://stackoverflow.com'. 

C’è un altro modo per caricare un web worker convertendo la funzione worker in una stringa e poi in un Blob e caricandolo come worker ma ho provato anche questo:

 var sharedWorkers = {}; var startSharedWorker = function(workerFunc){ var funcString = workerFunc.toString(); var index = funcString.indexOf('{'); var funcStringClean = funcString.substring(index + 1, funcString.length - 1); var blob = new Blob([funcStringClean], { type: "text/javascript" }); sharedWorkers.google = new SharedWorker(window.URL.createObjectURL(blob)); sharedWorkers.google.port.start(); }; 

E neanche questo funziona. Perché? Perché i lavoratori condivisi sono condivisi in base alla posizione da cui viene caricato il loro file worker. Poiché createObjectURL genera un nome file univoco per ciascun utilizzo , i worker non avranno mai lo stesso URL e quindi non saranno mai condivisi.

Come posso risolvere questo problema?


Nota: ho provato a chiedere soluzioni specifiche, ma a questo punto penso che il meglio che posso fare sia chiedere in modo più ampio qualsiasi soluzione al problema, dal momento che tutte le mie soluzioni tentate sembrano fondamentalmente impossibili a causa delle stesse politiche di origine o modo URL.createObjectURL funziona ( dalle specifiche , sembra imansible modificare l’URL del file risultante).

Detto questo, se la mia domanda può in qualche modo essere migliorata o chiarita, si prega di lasciare un commento.

È ansible utilizzare fetch() , response.blob() per creare un Blob URL di tipo application/javascript dal Blob restituito; imposta il parametro SharedWorker() Blob URL creato da URL.createObjectURL() ; utilizzare window.open() , load evento della window appena aperta per definire lo stesso SharedWorker precedentemente definito nella window originale, albind l’evento message a SharedWorker originale alle window aperte di recente.

javascript stato provato alla console su Come cancellare il contenuto di un iFrame da un altro iFrame , dove l’URL della domanda corrente deve essere caricato in una nuova tab con il message dalla window apertura attraverso il gestore di eventi worker.port.postMessage() registrato alla console .

La window apertura dovrebbe anche registrare l’evento del message quando inviato dalla window appena aperta usando worker.postMessage(/* message */) , in modo simile alla window apertura

 window.worker = void 0, window.so = void 0; fetch("https://cdn.rawgit.com/viziionary/Nacho-Bot/master/webworker.js") .then(response => response.blob()) .then(script => { console.log(script); var url = URL.createObjectURL(script); window.worker = new SharedWorker(url); console.log(worker); worker.port.addEventListener("message", (e) => console.log(e.data)); worker.port.start(); window.so = window.open("https://stackoverflow.com/questions/" + "38810002/" + "how-can-i-load-a-shared-web-worker-" + "with-a-user-script", "_blank"); so.addEventListener("load", () => { so.worker = worker; so.console.log(so.worker); so.worker.port.addEventListener("message", (e) => so.console.log(e.data)); so.worker.port.start(); so.worker.port.postMessage("hi from " + so.location.href); }); so.addEventListener("load", () => { worker.port.postMessage("hello from " + location.href) }) }); 

Alla console in entrambe le tab è quindi ansible utilizzare, ad esempio; a Come cancellare il contenuto di un iFrame da un altro iFrame worker.postMessage("hello, again") nella nuova window dell’URL corrente Come posso caricare un web worker condiviso con uno script utente? , worker.port.postMessage("hi, again"); dove gli eventi di message allegati a ciascuna window , la comunicazione tra le due window può essere ottenuta utilizzando l’originale SharedWorker creato all’URL iniziale.

condizione indispensabile

  • Come hai cercato e come è stato menzionato nei commenti, l’URL di SharedWorker è sobject alla stessa politica di origine.
  • Secondo questa domanda non c’è supporto CORS per l’URL di Worker .
  • In base a questo problema, il supporto GM_worker ora è un WONT_FIX, e sembra abbastanza vicino per essere imansible da implementare a causa di cambiamenti in Firefox. C’è anche una nota che Sandboxed Worker (al contrario di unsafeWindow.Worker ) non funziona neanche.

Design

Quello che suppongo tu voglia raggiungere è un @include * che includerà alcune statistiche o creerà alcune UI globali che appariranno ovunque. E quindi vuoi che un lavoratore mantenga alcuni aggregati statali o statistici in runtime (che saranno facilmente accessibili da ogni istanza di script utente), e / o vuoi eseguire una routine di calcolo pesante (perché altrimenti sarà siti di destinazione lenti verso il basso).

Nel modo di qualsiasi soluzione

La soluzione che voglio proporre è sostituire il design di SharedWorker con un’alternativa.

  • Se vuoi semplicemente mantenere uno stato nel lavoratore condiviso, usa semplicemente la memoria di Greasemonkey ( GM_setValue e gli amici). È condiviso tra tutte le istanze userscript (SQLite behide the scenes).
  • Se si desidera eseguire unsafeWindow.Worker di unsafeWindow.Worker in unsafeWindow.Worker e unsafeWindow.Worker risultati in Archiviazione Greasemonkey.
  • Se si desidera eseguire calcoli in background e devono essere eseguiti solo da una singola istanza, esistono numerose librerie di sincronizzazione “inter-window” (per lo più utilizzano localStorage ma Greasemomkey ha la stessa API, quindi non dovrebbe essere difficile scrivere un adattatore ad esso). In questo modo è ansible acquisire un blocco in un’istanza di userscript ed eseguire le routine in esso. Mi piace, IWC o ByTheWay ( probabilmente usato qui su Stack Exchange, post su di esso ).

Altro modo

Non sono sicuro, ma potrebbe esserci qualche ingegnoso spoofing della risposta, realizzato da ServiceWorker per far sì che SharedWorker funzioni come vorresti. Il punto di partenza è nella modifica di questa risposta .

Sono abbastanza sicuro che tu voglia una risposta diversa, ma purtroppo questo è ciò a cui si riduce.

I browser implementano politiche di origine identica per proteggere gli utenti di Internet e, sebbene le tue intenzioni siano chiare, nessun browser legittimo ti consente di cambiare l’origine di un utente condiviso.

Tutti i contesti di navigazione in un sharedWorker devono condividere la stessa origine esatta

  • ospite
  • protocollo
  • porta

Non puoi risolvere questo problema, ho provato a utilizzare iframe in aggiunta ai tuoi metodi, ma non funzionerà.

Forse puoi metterlo il tuo file javascript su github e usare il loro raw. servizio per ottenere il file, in questo modo è ansible farlo funzionare senza troppi sforzi.

Aggiornare

Stavo leggendo gli aggiornamenti di Chrome e mi sono ricordato che mi hai chiesto questo. I lavoratori di servizi di origine incrociata sono arrivati ​​su Chrome!

Per fare ciò, aggiungi quanto segue all’evento di installazione per il SW:

 self.addEventListener('install', event => { event.registerForeignFetch({ scopes: [self.registration.scope], // or some sub-scope origins: ['*'] // or ['https://example.com'] }); }); 

Sono necessarie anche altre considerazioni, verificarlo:

Link completo: https://developers.google.com/web/updates/2016/09/foreign-fetch?hl=it?utm_campaign=devshow_series_crossoriginserviceworkers_092316&utm_source=gdev&utm_medium=yt-desc