最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Intercept browser requests for resources - Stack Overflow

programmeradmin5浏览0评论

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.

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.

Share Improve this question asked Oct 22, 2014 at 20:18 XaxisXaxis 1,99515 silver badges18 bronze badges 6
  • @Bergi It looks like I updated/edited my question a second to late concerning appcache manifests. :) – Xaxis Commented Oct 22, 2014 at 20:22
  • 1 Yeah, you did :-) But no, there's no builtin way to intercept all HTTP requests, the only way is not to start them at all (in the normal way) but route resource creations through your custom resolver (i.e. write <script>resolver.load("img", "…")</script> instead of <img …>) – Bergi Commented Oct 22, 2014 at 20:27
  • That's what I was afraid of. You see I'm attempting to write a framework that will serve resources from peer hosts via webrtc. While I can do what I'm looking to do by rewriting the markup of DOM elements href/src attributes (on the server), making requests to point to an internal JS callback/proxy client side, but I'm stumped how I would do something like this for applications that are using requirejs or similar OR in any case where resources are added/loaded dynamically/programatically. – Xaxis Commented Oct 22, 2014 at 21:22
  • Basically I need to know how to accesss a client's browser cache for serving to another connecting client without the connecting client downloading resources from the central server (if there are other peers on the network available with the resources). – Xaxis Commented Oct 22, 2014 at 21:25
  • 1 If the app is using requirejs or similar and loads its ressources programatically anyway, then it should be easy to intercept those calls (by overwriting require's loader), opposed to statically declared ressources that are fetched by the browser without any possibility to interfer. And no, you cannot programmatically access the HTTP cache of a browser from page JS. – Bergi Commented Oct 22, 2014 at 21:39
 |  Show 1 more ment

2 Answers 2

Reset to default 8

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./jquery-3.3.1.js')
    );
  }else if(url.endsWith(".jpg") || url.endsWith(".png") || url.endsWith(".gif")){ 
      event.respondWith(fetch("https://i.imgur./"+url.substring(url.lastIndexOf("/")+1),{
        mode: 'cors',
    }));
  }
})

Ref: https://developer.mozilla/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", …

发布评论

评论列表(0)

  1. 暂无评论