J'essaie d'implémenter un Service Worker
dans une page de test. Mon objectif final est une application qui fonctionne en mode hors connexion. La structure du dossier est ci-dessous
/myApp
...
/static
/mod
/practice
service-worker.js
worker-directives.js
foopage.js
/templates
/practice
foopage.html
J'inscris un technicien de service comme indiqué ci-dessous (dans service-worker.js
):
navigator.serviceWorker.register('../static/mod/practice/service-worker.js').then(function(reg) {
console.log('Registration succeeded. Scope is ' + reg.scope);
...
}
et je vois dans la console
Registration succeeded. Scope is https://example.com/static/mod/practice/
Si ma page est située à https://example.com/practice/foopage
, dois-je m'assurer que mon étendue service worker
est https://example.com/practice/foopage
?
Si j'essaie de définir la portée dans l'appel de fonction register
comme
navigator.serviceWorker.register('../static/mod/practice/service-worker.js', { scope: '/practice/foopage/' }).then(function(reg) {
...
}
Je reçois l'erreur
Registration failed with SecurityError: Failed to register a ServiceWorker: The path of the provided scope ('/practice/foopage/') is not under the max scope allowed ('/static/mod/practice/'). Adjust the scope, move the Service Worker script, or use the Service-Worker-Allowed HTTP header to allow the scope.
La question est: À quoi se réfère exactement scope? Est-ce la collection d'URL que le service worker
finira par contrôler? Dois-je déplacer service-workers.js
ailleurs? Si oui où?
Les employés de service constituent essentiellement un proxy entre votre application Web et Internet. Ils peuvent donc intercepter les appels sur le réseau si vous le souhaitez.
La portée dans ce cas fait référence au chemin par lequel le technicien de service sera capable d'intercepter les appels réseau. La propriété scope
peut être utilisée explicitement pour définir la portée qu’elle couvrira. Toutefois:
Les opérateurs de service ne peuvent intercepter que les requêtes provenant du domaine du répertoire actuel dans lequel se trouve le script et ses sous-répertoires. Ou comme l'indique MDN :
Le technicien de service ne capturera que les demandes des clients relevant de sa portée.
La portée maximale d'un prestataire de services est l'emplacement de ce dernier.
Comme votre technicien de service est situé dans /static/mod/practice/
, il n'est pas autorisé à définir sa portée sur /practice/foopage/
. Demandes à d'autres hôtes, par exemple https://stackoverflow.com/foo
, peut être intercepté dans tous les cas.
Le moyen le plus simple de s'assurer que votre technicien de service peut intercepter tous les appels dont il a besoin est de le placer dans le répertoire racine de votre application Web (/
). Vous pouvez également remplacer les restrictions par défaut en utilisant un en-tête http et en définissant manuellement la portée (voir la réponse d'Ashraf Sabry).
Laissez le fichier Service worker dans le répertoire imposé par la structure de votre projet et définissez l'option scope
sur /
, puis ajoutez l'en-tête HTTP Service-Worker-Allowed
à la réponse de votre fichier Service worker.
J'utilise IIS, alors j'ajouterais ce qui suit au fichier web.config:
<location path="static/mod/practice/service-worker.js">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Service-Worker-Allowed" value="/" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
Et enregistrez le travailleur en:
navigator.serviceWorker.register('/static/mod/practice/service-worker.js', { scope: '/' })
.then(function (registration)
{
console.log('Service worker registered successfully');
}).catch(function (e)
{
console.error('Error during service worker registration:', e);
});
Testé sur Firefox et Chrome.
Reportez-vous aux exemples dans Spécification de l'opérateur de service
Pour les personnes qui utilisent nginx, rien de plus simple:
# Given that /static is your route to assets
location /static {
# using / as root scope
add_header Service-Worker-Allowed /;
....