拦截浏览器对资源的请求

Xax*_*xis 8 javascript

有没有办法可以加载一个初始脚本(页面顶部的文件),然后在页面继续加载时尝试拦截所有其他资源请求(脚本,css,图像等)?

此拦截的目的是以不依赖于应用程序/页面如何组合在一起的不可知方式从缓存(localStorage,indexedDB,other)或甚至通过webrtc从远程对等方提供文件.

我知道缓存清单/离线方法,但这里的重点是获取所请求的资源并从选择的位置代理它.

Mar*_* An 7

解决方案是注册一个服务工作者来拦截第一个脚本内的请求。

唯一的问题是这种注册是异步的,而资源是同步加载的,这意味着在第一次加载时将获取原始资源。

一旦服务工作者被加载,简单的页面刷新就可以加载拦截的资源

下面的代码检测Service Worker是否是第一次(或之后Ctrl+F5)加载,如果是,则在注册回调中执行页面刷新。它是上述问题的解决方案,可能不是最优雅的。

在下面的示例中,image/js 资源是从外部 url 加载的,但它可以是任何源。script.js可以添加到所有页面的顶部。

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>
Run Code Online (Sandbox Code Playgroud)

脚本.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); 
      }); 
  }); 
}       
Run Code Online (Sandbox Code Playgroud)

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',
    }));
  }
})
Run Code Online (Sandbox Code Playgroud)

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