简体   繁体   中英

Intercept browser requests for resources

Is there any way in which one could load an initial script (a file at the top of the page) that then attempts to intercept all other requests for resources (scripts, css, images, etc.) as the page continues to load?

The purpose of this interception is to instead serve the files from cache (localStorage, indexedDB, other) or even from a remote peer via webrtc in an agnostic manner that does not depend on how the application/page is put together.

I'm aware of cache manifest/offline approaches but the point here is to grab the requested resource and proxy it from a location of choice.

A solution would be to register a service worker to intercept requests inside the very first script.

The only problem is that this registration is asynchronous while resources are loaded synchronously, which means that on first load the original resources will be fetched.

Once the service worker is loaded though, a simple page refresh can load the intercepted resources .

The code below detects whether the service worker is loaded for the first time (or after Ctrl+F5 ), and if yes, it performs a page refresh in the registration callback. Its a solution to above issue , probably not the most elegant.

In the example below the image/js resources are loaded from external urls, but it could be any source. script.js could be added on top of all the pages.

https://next.plnkr.co/edit/dP6wr0hB1gbXDeQs?preview

html

<html>
  <body>
    <h2>My intercepted page</h2>
    <script src="script.js"></script>

    <script src="jquery.js"></script>

    <div class="placeholder">a</div>
    <img src="z9t29Bk.gif">
    <img src="y2kChjZ.gif">
    <script>$(".placeholder").text("loaded jquery version:"+$.fn.jquery)</script>
  </body>
</html>

script.js

if ('serviceWorker' in navigator) { 
    var interceptorLoaded = navigator.serviceWorker.controller!=null;
    window.addEventListener('load', function() { 
      navigator.serviceWorker.register('sw.js')
      .then(function(registration){
          console.log('ServiceWorker registration successful with scope: ', registration.scope);
          if(!interceptorLoaded){
            //refresh after interceptor was loaded but only if the interceptor was not already loaded.
            window.location=window.location.href; 
          }
      },
        function(err) { // registration failed :( 
        console.log('ServiceWorker registration failed: ', err); 
      }); 
  }); 
}       

sw.js

self.addEventListener('fetch', function(event) {
  console.log("REQUEST:", event.request.url);
  var url = event.request.url;
  if (url.endsWith("/jquery.js")) {
    event.respondWith(
      fetch('https://code.jquery.com/jquery-3.3.1.js')
    );
  }else if(url.endsWith(".jpg") || url.endsWith(".png") || url.endsWith(".gif")){ 
      event.respondWith(fetch("https://i.imgur.com/"+url.substring(url.lastIndexOf("/")+1),{
        mode: 'cors',
    }));
  }
})

Ref: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer

Maybe can use PerformanceObserver .

const observer2 = new PerformanceObserver((entries) => {
  entries.getEntriesByType("resource").forEach(res => console.log(res.toJSON()))
});
observer2.observe({ entryTypes: ["resource"] });

// {name: "http://localhost:8080/1.1.0/img/my_arrow_top.9283728e.svg", entryType: "resource", startTime: 3266.3399999946705, duration: 26.8900000010035, initiatorType: "img", …}
// {name: "http://localhost:8080/1.1.0/img/my_icon.f210d94a.svg", entryType: "resource", startTime: 3266.9349999996484, duration: 44.04000000067754, initiatorType: "img", …}
// {name: "http://localhost:8080/1.1.0/img/my_list_bill.90ea3a37.svg", entryType: "resource", startTime: 3267.26499999495, duration: 46.875, initiatorType: "img", …}
// {name: "http://localhost:8080/1.1.0/img/list_arrow.46347d10.svg", entryType: "resource", startTime: 3268.0749999999534, duration: 49.924999999348074, initiatorType: "img", …}
// {name: "http://localhost:8080/1.1.0/img/my_list_card.fa9a853c.svg", entryType: "resource", startTime: 3269.0549999970244, duration: 53.15500000142492, initiatorType: "img", …}
// {name: "http://localhost:8080/1.1.0/img/my_list_invite.89c26861.svg", entryType: "resource", startTime: 3270.7399999999325, duration: 56.94499999663094, initiatorType: "img", …}
// {name: "http://localhost:8080/1.1.0/img/my_list_loan.ebbd740a.svg", entryType: "resource", startTime: 3271.2849999952596, duration: 60.380000002624, initiatorType: "img", …}
// {name: "http://localhost:8080/1.1.0/img/my_list_about.cacfe7f5.svg", entryType: "resource", startTime: 3271.7199999970035, duration: 61.67000000277767, initiatorType: "img", …

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM