smnbbrv / ngx-plyr

Angular 6+ binding for Plyr video & audio player
https://smnbbrv.github.io/ngx-plyr/
MIT License
100 stars 65 forks source link

Guide: How to Add Headers to HTTP Request (send by Plyr) #60

Open KangHidro opened 4 years ago

KangHidro commented 4 years ago

Maybe you will encountered the case that Video need Auth Token to fetch, so I hope my guide may help you a litle bit! Thanks to @Ashesh3! https://github.com/sampotts/plyr/issues/1312#issuecomment-677267757

  1. Create service worker JS file (e.g. sw.js), place it in some where (e.g. src/assets/js/service-worker/). File content is:
    
    let domainInclude = ''; // Recieve from Component
    let authToken = ''; // Recieve from Component

self.addEventListener('install', event => { const params = new URL(location); domainInclude = params.searchParams.get('include'); authToken = params.searchParams.get('token'); const installCompleted = Promise.resolve() .then(() => {}); event.waitUntil(installCompleted); });

self.addEventListener('activate', event => { event.waitUntil( self.clients.claim(), caches.keys().then((cacheNames) => { return Promise.all( cacheNames.map((cache) => { if (cache !== cacheName) { return caches.delete(cache); } }) ); })); });

// This function is implement from the guide of @Ashesh3 self.addEventListener('fetch', event => { if (event.request.url.includes(domainInclude)) { event.respondWith(customHeaderRequestFetch(event)); } });

function customHeaderRequestFetch(event) { const newRequest = new Request(event.request, { mode: "cors", credentials: "omit", //also supports partial content (seeking) headers: { range: event.request.headers.get("range") != undefined ? event.request.headers.get("range") : "0-", Authorization: authToken } }); return fetch(newRequest); }

2. Edit file `angular.json`:
Path: `projects` > `<your-pj-name>` > `architect` > `build` > `options` > `assets`:

"assets": [ .......... { "glob": "*/", "input": "src/assets/js/service-worker/", "output": "/" } .......... ]

3. Go to your Component, where you want to start Service Worker:

ngOnInit() { if ('serviceWorker' in navigator) { // Make sure browser support Service Worker navigator.serviceWorker.register(/sw.js?include=${encodeURIComponent('<URL_MATCHING>')}&token=${<YOUR_TOKEN>}, { scope: '' }) .then(registration => registration.unregister()); // SW unregistered still working till page reload, so don't worry. // But if you don't unregister here, Component may get stuck when you reload page, // because old SW is fetching video and not done yet. // In this case, If you stop playing video a while, page can be reload. } else { window.alert('Browser not support Service Worker.'); } }


Note:
- `<URL_MATCHING>`: Send to `sw.js`, using to check matching the endpoint you need to add Headers.
E.g. `/api/video/`: If Request URL include `/api/video/` then `sw.js` will adding Headers to the request. (http://backend.local/api/video/aaaaa)
- `<YOUR_TOKEN>`: Token send to `sw.js` for attach to Headers.
- `<SCOPE>`: Router link where `sw.js` will working, e.g. `/view-video/` (http://localhost:4200/view-video/aaaaa)

P/s: I re-open this issues because Github hide closed issues automatically, so keep this open will make others easy to find :D
Ashesh3 commented 4 years ago

Nice guide! I'm glad we were able to solve this problem.

Suroor-Ahmmad commented 4 years ago

@KangHidro I tried to implement this and works fine, but I wonder why it doesn't work in some cases. Sometimes token is not getting attached in the request, even though I can see SW running, I see only this specific request is not fetched by the SW, I have to refresh the page to get it working, and also if I unregister SW, sometimes I get error DOMException: Only the active worker can claim clients.. any help/suggestion will be appreciated (Ps. I have very less idea about service-workers)

KangHidro commented 4 years ago

@Suroor-Ahmmad I'm also new and have no idea about SW,

Sometimes token is not getting attached in the request, even though I can see SW running

You can modify sw.js for check workflow of codes:

self.addEventListener('fetch', event => {
  console.log('Request had addEventListener fetch'); //////////////////////////
  if (event.request.url.includes(domainInclude)) {
    console.log('Request had correct domain'); //////////////////////////
    event.respondWith(customHeaderRequestFetch(event));
  }
});

function customHeaderRequestFetch(event) {
  console.log('Request go into customHeaderRequestFetch'); //////////////////////////
  const newRequest = new Request(event.request, {

If the error frequency is low as acceptable level, I think refresh the page is the most optimal way.

-- If I got the same error with you (and I can fix it), I will let you know :D