I am currently working on a project that requires me to modify all the fetch requests of my site's iframes
I'm using a service worker to intercept all the requests from my browser, but I don't get the iframe requests...
sw.js
self.addEventListener('activate', function (event) {
console.log('Claiming control');
return self.clients.claim();
});
self.addEventListener('fetch', function (event) {
console.log(event.request.url)
});
handler.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js', {
scope: "/"
}).then(function (registration) {
console.log('Service worker registered with scope: ', registration.scope);
}, function (err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
index.html
<body>
<script src="./scripts/JS/handler.js"></script>
<iframe src="https://vitejs.dev/" frameborder="0"></iframe>
</body>
Here is my chrome console
What did I do wrong ?
Thanks in advance
PS : the activate message (Claiming control) doesn't appear too
Related
I have been researching the google analytics api (GA4) for the past day. And I want to be able to use GA4 api functions like runReport on the client-side. There is a piece of analytics that I want each of my web-clients to see.
Here is the code that I pulled out from the gapi documentation.
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for analyticsdata.properties.runReport
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/code-samples#javascript
*/
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/analytics https://www.googleapis.com/auth/analytics.readonly"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey("FILLED_THIS_WITH_MY_API_KEY");
return gapi.client.load("https://analyticsdata.googleapis.com/$discovery/rest?version=v1beta")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
function execute() {
return gapi.client.analyticsdata.properties.runReport({
"resource": {}
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client:auth2", function() {
gapi.auth2.init({client_id: "FILLED_THIS_WITH_MY_CLIENT_ID"});
});
</script>
<button onclick="authenticate().then(loadClient)">authorize and load</button>
<button onclick="execute()">execute</button>
And it gives me this error:
gapi.auth2.ExternallyVisibleError: Invalid cookiePolicy\
Basicly I'm trying to accomplish to show a dialog when a new serviceworker version has been detected, and then to have user decide to reload to fetch it. To accomplish this we need to actively set skipWaiting before we reload window.
Here's my action:
onClickHandler = () => {
console.log('on click', 'posting skipWaiting');
navigator.serviceWorker.controller.postMessage('skipWaiting');
};
Here's my attempt to create the eventListener:
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
console.log('worker state', installingWorker.state);
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed.'
);
navigator.serviceWorker.addEventListener('message', event => {
console.log('skip waiting');
if (event.data === 'skipWaiting') {
self.skipWaiting();
}
});
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
The issue is that navigator.serviceWorker.addEventListener('message', event => does not get triggered. Am I declaring the listener wrong?
You are close. In your installed block you can make a check for
navigator.serviceWorker.controller
If this exists it means that the old content will have been purged and the fresh content will have been added to the cache. Its a perfect time to display a message or to force a refresh.
navigator.serviceWorker.register('service-worker.js').then(function (registration) {
$log.debug('The service worker has been registered ', registration);
if(navigator.online) {
toastr.warning('Offline Mode', 'Application Status');
}
// updatefound is fired if service-worker.js changes.
registration.onupdatefound = function () {
// The updatefound event implies that reg.installing is set; see
// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
var installingWorker = registration.installing;
installingWorker.onstatechange = function () {
switch (installingWorker.state) {
case 'installed':
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and the fresh content will
// have been added to the cache.
// It's the perfect time to display a "New content is available; please refresh."
// message in the page's interface.
toastr.info('Application has been updated, please refresh this page for the most recent version');
window.location.reload();
});
caches.delete('scope-dynamic').then(function () {
$log.debug('Killed the dynamic cache!');
})
$log.debug('New or updated content is available.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a "Content is cached for offline use." message.
toastr.success('Content is cached for offline use.', 'Application Status');
$log.debug('Content is now available offline!');
}
break;
case 'redundant':
$log.error('The installing service worker became redundant.');
break;
}
};
};
}).catch(function (e) {
$log.error('Error during service worker registration:', e);
});
There is some angular stuff sprinkled in there but that should help you get to where you wanna be.
The problem here is that the code you provided has only defined receiving & sending messages from your client to the service worker.
The below method has defined a message to be sent to your controller (active) service worker.
onClickHandler = () => {
console.log('on click', 'posting skipWaiting');
navigator.serviceWorker.controller.postMessage('skipWaiting');
};
The definition below has added an event listener on your ServiceWorker container to receive any messages sent from the service worker.
navigator.serviceWorker.addEventListener('message', event => {
console.log('skip waiting');
if (event.data === 'skipWaiting') {
self.skipWaiting();
}
});
You now need to define the event handlers from the service worker file to receive & send messages.
In the service worker file, to receive messages from the client:
self.addEventListener('message', function handler (event) {
console.log('skip waiting');
if (event.data === 'skipWaiting') {
self.skipWaiting();
}
});
To send messages from serviceworker to your client:
self.addEventListener('fetch', function(event) {
self.clients.matchAll().then(all => all.map(client => client.postMessage('data from webworker')));
});
You could also send data back from the serviceworker using a MessageChannel. On your client you would have to define something like below:
navigator.serviceWorker
.register(swUrl)
.then(registration => {
var messageChannel = new MessageChannel();
// listener for messages from the ServiceWorker
messageChannel.port1.addEventListener('message', (event) => console.log(event.data));
function sendMessage (message) {
//send message to the active service worker
navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
}
onClickHandler = () => {
sendMessage('skipWaiting');
};
});
I found the below article to be quite helpful.
ServiceWorker, MessageChannel & postMessage by Nicolás Bevacqua
I am basically caching an offline page and loading it when my website is offline.
For this I have created a page say 'signIn' and the javascript file of 'SignIn' is javascript->pages->signIn here I have initiated the service worker like
javascript/page/script.js
if('serviceWorker' in navigator){
navigator.serviceWorker.register('./sw1.js').then(function(reg){
console.log("Service workers registered");
});
}
else{
console.log("Browser doesnt support service workers");
}
})
The sw1.js and the offline.html is basically in the same folder as the page SignIn.
self.addEventListener('install', function(event) {
var offlineRequest = new Request('./offline.html');
event.waitUntil(
fetch(offlineRequest).then(function(response) {
return caches.open('offline').then(function(cache) {
console.log('[oninstall] Cached offline page', response.url);
return cache.put(offlineRequest, response);
});
})
);
});
self.addEventListener('fetch', function(event) {
var request = event.request;
if (request.method === 'GET') {
console.log(request);
event.respondWith(
fetch(request).then(function(response){
console.log("From Network "+response);
return response;
}).catch(function(error) {
console.log(
'[onfetch] Failed. Serving cached offline fallback ' +
error
);
return caches.open('offline').then(function(cache) {
console.log("Opened Cache");
return cache.match('./offline.html');
});
})
);
}
});
Basically things work fine when I am online but When i am offline I get the following error in chrome-dev-tools-applications .
Please Help me.
I'm implementing Push Notifications in my app. I made a service-worker to show the notification in my browser (Chrome).
Now, I need to call a function that it's inside an Angular Controller. I was trying to make an event like this in my service worker.
self.addEventListener('push', function(event) {
event.waitUntil(
fetch(self.CONTENT_URL, {headers: headers})
.then(function(response) {
if (response.status !== 200) {
}
return response.json().then(function(data) {
/* some stuff*/
document.dispatchEvent('myEvent');
return notification;
});
})
);
});
In this event I handle the notification and I'm trying to use an event.
In the controller I wrote the code below
document.addEventListener('myEvent', function(){
console.log("im here");
});
But the browser doesn't show the console.log()
Any ideas to complete this task? Thanks a lot!
Here is what I did for communications between angular (or anything at the window/document side) with Service Worker
Somewhere in your angular app.
if ('serviceWorker' in navigator) {
// ensure service worker is ready
navigator.serviceWorker.ready.then(function (reg) {
// PING to service worker, later we will use this ping to identifies our client.
navigator.serviceWorker.controller.postMessage("ping");
// listening for messages from service worker
navigator.serviceWorker.addEventListener('message', function (event) {
var messageFromSW = event.data;
console.log("message from SW: " + messageFromSW);
// you can also send a stringified JSON and then do a JSON.parse() here.
});
}
}
At the start of your service worker
let angularClient;
self.addEventListener('message', event => {
// if message is a "ping" string,
// we store the client sent the message into angularClient variable
if (event.data == "ping") {
angularClient = event.source;
}
});
When you receive a push
// In your push stuff
self.addEventListener('push', function(event) {
event.waitUntil(
fetch(self.CONTENT_URL, {headers: headers})
.then(function(response) {
if (response.status !== 200) {
}
return response.json().then(function(data) {
/* some stuff*/
angularClient.postMessage('{"data": "you can send a stringified JSON here then parse it on the client"}');
return notification;
});
})
);
});
I am implementing chrome push notification for my website users. Which I am able to do successfully.
I have two question ?
1) how to get the previous subscription id whenever i block the notification from browser setting. I have to remove the subscription id from my backend server
2) whenever i reload the website pushManager.subscribe method is running every time in which i am sending subscription id to server due to which the API is hitting every time with same subscription id
push.js
'use strict';
if ('serviceWorker' in navigator) {
console.log('Service Worker is supported');
navigator.serviceWorker.register('service_worker.js').then(function() {
return navigator.serviceWorker.ready;
}).then(function(reg) {
console.log('Service Worker is ready :^)', reg);
reg.pushManager.subscribe({userVisibleOnly: true}).then(function(sub) {
console.log('endpoint:',JSON.stringify(sub.endpoint));
console.log(sub.endpoint.substring('https://android.googleapis.com/gcm/send/'.length));
});
}).catch(function(error) {
console.log('Service Worker error :^(', error);
});
}
service-worker.js
'use strict';
var myurl;
console.log('Started', self);
self.addEventListener('install', function(event) {
self.skipWaiting();
console.log('Installed', event);
});
self.addEventListener('activate', function(event) {
console.log('Activated', event);
});
self.addEventListener('push', function(event) {
console.log('Push message', event);
event.waitUntil(
fetch('/notify.json').then(function(response) {
return response.json().then(function(data) {
console.log(JSON.stringify(data));
var title = data.title;
var body = data.body;
myurl=data.myurl;
return self.registration.showNotification(title, {
body: body,
icon: 'profile.png',
tag: 'notificationTag'
});
});
}).catch(function(err) {
console.error('Unable to retrieve data', err);
var title = 'An error occurred';
var body = 'We were unable to get the information for this push message';
return self.registration.showNotification(title, {
body: body,
icon: 'profile.png',
tag: 'notificationTag'
});
})
);
});
// var title = 'Vcona';
// event.waitUntil(
// self.registration.showNotification(title, {
// 'body': 'School Management',
// 'icon': 'profile.png'
// }));
self.addEventListener('notificationclick', function(event) {
console.log('Notification click: tag', event.notification.tag);
// Android doesn't close the notification when you click it
// See http://crbug.com/463146
event.notification.close();
var url = 'https://demo.innotical.com';
// Check if there's already a tab open with this URL.
// If yes: focus on the tab.
// If no: open a tab with the URL.
event.waitUntil(
clients.matchAll({
type: 'window'
})
.then(function(windowClients) {
console.log('WindowClients', windowClients);
for (var i = 0; i < windowClients.length; i++) {
var client = windowClients[i];
console.log('WindowClient', client);
if (client.url === url && 'focus' in client) {
return client.focus();
}
}
if (clients.openWindow) {
return clients.openWindow(myurl);
}
})
);
});
Best pieces of advice I can give:
Keep track of your subscription (especially what you send to your server) in indexDB. Why IndexDB?
You can update indexDB in the window and in the serviceworker. This is important as you'll first get a PushSubscription in the window, but serviceworker will dispatch pushsubscriptionchange events which you should listen for and attempt to get a new PushSubscription, if you can.
When the page loads, check indexDB for an old subscription, if it exists, compare it to getSubscription() (i.e. your current subscription). This check should include any values you need server side, for example, when browsers go from not supporting payloads, to supporting them, they go from having no keys, to suddenly having keys - so you should check if you server has these keys or not.
DO NOT USE any of the API's for GCM, this will NOT work on other browsers (Firefox, Opera, Samsung Browser + others in the future) and aren't needed.
1) You can't get previous reg id. There are to ways:
Every time you subscribe for notifications you can save it to a local chrome db(for example indexdb) and when you subscribe another time you just restore you previous reg id from this db.
When you send a notification to GCM it responds you with canonical ids and another information about correctness of reg ids, so you can remove invalid one
2) You have to check first if subscription id already exists, then subscribe if not:
if ('serviceWorker' in navigator) {
console.log('Service Worker is supported');
navigator.serviceWorker.register('service_worker.js').then(function() {
return navigator.serviceWorker.ready;
}).then(function(reg) {
console.log('Service Worker is ready :^)', reg);
reg.pushManager.getSubscription().then(function(subscription) {
if(!subscription) {
reg.pushManager.subscribe({userVisibleOnly: true}).then(function(sub) {
console.log('endpoint:',JSON.stringify(sub.endpoint));
console.log(sub.endpoint.substring('https://android.googleapis.com/gcm/send /'.length));
//send new subscription id to server
return;
});
}
});
}).catch(function(error) {
console.log('Service Worker error :^(', error);
});
}