headLoader.js

headLoader.js(v3.1.1)借助indexedDB数据库实现网站快速加载。原理是在恰当时间将网站数据缓存到浏览器的数据库indexedDB,例如JS、CSS、JSON、图片等,使网站页面下次加载或刷新时,迅速的从indexedDB数据库获取有效资源,从而缩短响应时间。

  • 主要功能:资源加载、预加载、热加载、跨页缓存管理、localStorage API、代码保护及隐藏等。
  • 网站加速:由于使用纯前端的数据库缓存技术,基本上用"0成本"就能使普通的网站得到明显的加速及优化。
  • 使用场景:其"按需加载"和"跨页缓存共享"等特点,可胜任大型网站对服务器高频资源海量请求的痛点。
快速上手
<script type="text/javascript" data-dir="/" data-js="61886f0745c74ed2,438ebd06460eb7e8,d3e8a055ff14521a,20e5e4f682e662dd" data-css="61886f0745c74ed2,438ebd06460eb7e8,d3e8a055ff14521a" src="/87ce85eb5c1d99f3.js"></script>

以上代码为采用了headLoader.js技术,它可实现如下常规页面加载代码的功能


          <script type="text/javascript" src="/61886f0745c74ed2.js"></script>
<script type="text/javascript" src="/438ebd06460eb7e8.js"></script>
<script type="text/javascript" src="/d3e8a055ff14521a.js"></script>
<script type="text/javascript" src="/20e5e4f682e662dd.js"></script>
<link rel="stylesheet" href="/61886f0745c74ed2.css" type="text/css">
<link rel="stylesheet" href="/438ebd06460eb7e8.css" type="text/css">
<link rel="stylesheet" href="/d3e8a055ff14521a.css" type="text/css">

headerLoader.js不仅能实现上述功能,还会自动将资源缓存到indexedDB,当刷新页面或者其它页面再次请求该资源时,直接从缓存读取而不会有额外的网络请求。

插件介绍
  • 可实现一个script标签加载页面所需的全部css及js文档;
  • 支持"js","css","svg","text","xml","json","html","htm"等文本文件的读取;
  • 支持图片、视频、字体、图标库等二进制文件类型的读取;
  • 当页面刷新或者重新载入时,会从缓存中优先读取,缩短响应时间,减少页面载入时的闪烁;
  • 可实现资源预加载功能,即加载完成后存入缓存,当其它页面需要时从缓存快速读取;
  • 资源热加载,即加载完成后自动应用,而不需要刷新页面;
  • 缓存生命周期可自定义,即能复用本地缓存又能保证代码的时效性;
  • 缓存生命周期结束后,如果服务器文件未修改,继续使用本地缓存,进一步减少网络流量提高效率;
  • 生产环境并行加载文档加快速度,开发环境串行加载利于观察程序运行;
  • 生产环境程序在内存中运行便于保护及隐藏代码,开发环境正常在页面中运行方便调试与定位;
  • 提供localStorage API,支持存储任意类型数据(数组、对象等),跨页面共享,严格遵守生命周期;
  • 从v2.0.0版本后使用现代浏览器的indexedDB数据库存储缓存数据,容量不再受限制,尽可用它构建更大规模的项目。
使用方法

headLoader的使用方法有标签属性定义法和命令行语句法,可以任选其一,而对于更复杂的逻辑要求,也可以混合使用,比如用标签属性定义法加载调度和配置文件,在调度和配置文件中用命令行语句法来实现更灵活的加载.下面介绍一下两种方法的具体使用:

1.标签属性定义法

<script type="text/javascript" data-dir="/media/" data-css="public/d96b970cf94e1fbd,96ab3a9797723b31,_css" data-js="libs/7895c75404118ace,libs/1788036618785f9a,_js" data-font="font/a.woff,font/b.woff" data-file="html/61886f0745c74ed2.html,svg/61886f0745c74ed2.svg"  src="/media/js/libs/87ce85eb5c1d99f3.js"></script><!--引入js-->

2.使用代码程序的方法

也可以先让headLoader.js先加载一个调度文件,然后在调度文件中使用代码程序加载更多的文件,当然还是要首先引入headLoader.js

<script type="text/javascript" src="/media/js/libs/87ce85eb5c1d99f3.js"></script><!--引入js-->

然后使用javascript定义

 // 方法一:构造函数自动加载(推荐)
let loader=new headLoader({
  dataDir:"/media/",
  dataCss:['public/css1','public/css2','_css'],
  dataJs:['libs/jquery-3.1.0','libs/jquery.elfAlert','_js'],
  dataFont:['font/a.woff','font/b.woff'],
  dataFile:['html/a.html','svg/a.svg'],
  lifeCycle:24,
  showLog:false,
  preload:0, // 0:加载后立即应用 1:只存储不应用
  callback:function(_data){console.log(_data)}
});
// 资源自动加载,无需手动调用

// 方法二:手动加载
let loader2=new headLoader();
loader2.dataDir="/media/";
loader2.dataCss=['public/css1','public/css2','_css'];
loader2.dataJs=['libs/jquery-3.1.0','libs/jquery.elfAlert','_js'];
loader2.dataFont=['font/a.woff','font/b.woff'];
loader2.dataFile=['html/a.html','svg/a.svg'];
loader2.lifeCycle=24;
loader2.preload=0;
loader2.callback=function(_data){console.log(_data)};
await loader2.load(); // 手动触发加载
// load()结果没有值时返回:false
// load()结果有多个值时返回Map值:{"/media/css/public/css.css":value, ...}
//注意Map取值用get方法。
const result=await loader2.load();
if(result) console.log(result.get("/media/css/public/css.css").value);
          

标签属性定义法、命令行语句法在定义时需要特别注意命名方法和大小写的区别,特列下表:

标签属性定义法命令行语句法
资源路径data-dirdataDir
CSS资源data-cssdataCss
JS资源data-jsdataJs
字体资源data-fontdataFont
更多类型的资源data-filedataFile
缓存生命周期data-lifecyclelifeCycle
每次缓存生命周期延迟data-cycledelaycycleDelay
线下与线上路径是否自动切换data-activedataActive
是否显示加载统计data-showlogshowLog
预加载开关(未提供)preload
生命周期计算方法

在实例化headLoader时有一个生命周期参数lifeCycle,用来定义从2000/1/1零点以来每lifeCycle小时更新一次数据。
获取更新时间点有如下作用:
对于网站管理者,要选择合适的时间点关闭网站,直到网站更新完毕。
对于用户,在更新时间点后打开网页将会使所需数据与服务器保持同步。
由于存储在客户端的数据都有一个有效期限,为了避免用户端加载的数据模块不能兼容,网站版本更新一定要算好生命周期时间点再进行操作。

因此,网站新版本上线最好按照数据的生命周期计算的时间节点来完成。

1.为了方便获取下次更新时间,掌握网站更新时机,可以用下面的方法计算:

let loader=new headLoader();
//如果每36小时更新一次,获取下次更新时间
loader.nextLife(36);
//返回一个日期格式的字符串,例如 '2022/5/21 12:00:00'
//如果每24小时更新一次,每次更新延迟3小时,获取下次更新时间
loader.nextLife(24,3);
//返回一个日期格式的字符串,例如 '2022/5/21 3:00:00'
          

2.您也可以试试这个工具:

  • 生命周期:

    -+

    小时//对应参数 lifeCycle
  • 每次延迟:

    -+

    小时//对应参数 cycleDelay
  • 计算未来:
    更新时间点
  • 开始计算恢复默认
强制更新缓存方法

方法一:通过给headLoader.js路径修改不同的时间参数,可以强制更新生成的缓存数据。

例如:原来页面插入headLoader.js脚本如下:

<script type="text/javascript" src="/media/js/libs/87ce85eb5c1d99f3.js?v=2022-05-25"></script><!--引入js-->

现在,将路径时间参数"v=2022-05-25"修改为"v=2026-08-17",即可强制重新加载最新的数据并更新缓存,示例如下:

<script type="text/javascript" src="/media/js/libs/87ce85eb5c1d99f3.js?v=2026-08-17"></script><!--引入js-->

友情提示

  • 参数必须采用时间格式或时间戳,例如"2026-03-18",使用其它形式的参数不会触发强制更新缓存的功能。
  • 强制更新缓存后会记录时间戳参数,其它的页面要统一参数。

方法二:采用JS代码方法强制更新缓存方法


let loader=new headLoader();
await loader.db.expire();
          

友情提示

  • 该方法会使网站资源全部过期,执行后需要刷新页面,headLoader.js会自动触发更新命令,并只对更改过的文件进行更新。
强制删除缓存方法

let loader=new headLoader();
//删除缓存数据库,执行后需要刷新页面,否则可能造成模块缺失。
await loader.db.delete();
          

友情提示

  • 强制删除缓存后重新刷新页面会有一定的时间重新加载,时间长短依据网络质量和数据包大小,请知晰;
  • 此方法用于异常情况下的急救措施,正常情况下程序会根据默认的生命周期自动差异化更新数据。
JS/CSS预加载

在用户操作的空闲期间,将必要的资源预加载并保存到indexedDB,在用户切换到其它页面时,headLoader直接从indexedDB中获取,减少网络请求给页面渲染造成的卡顿。

一个预加载实例(您可以根据需要增加其它参数):

let loader=new headLoader();
loader.dataDir="/media/";
loader.dataCss=['css1','css2'];
loader.dataJs=['js1','js2'];
loader.preload=1; // 预加载模式:只存储到缓存,不应用到当前页面
await loader.load();
          

以上代码实现将以下资源预加载:


/media/css/css1.css
/media/css/css2.css
/media/js/js1.js
/media/js/js2.js
            

预加载利用闲时加载资源,当前页面或者其它页面需要时,将会直接从缓存中无延迟的加载,以达到快速响应的目的。

JS/CSS热加载

当程序运行过程中,headLoader可实现热加载,实现对模块随需随加载。

例如程序在运行过程中,需要xxx.js模块,而页面之前又未加载该资源,那么可以用如下方法实现热加载:

let hotLoad=async function(_module){
  let loader=new headLoader();
  loader.dataDir="/media/";
  loader.dataJs=[_module];
  return await loader.load();
}
//假设模块路径为"/media/libs/xxx.js"
hotLoad("libs/xxx").then(_=>console.log(_));
          

热加载适用于代码较大但是又不确定是否会调用的脚本资源。

加载并缓存字体

headLoader可以将一些操作系统没有的字体缓存下来,使整个网站所有页面再次使用时可以快速载入。

例如网站需要使用elf_round字体,而操作系统又没有安装这个字体,如果使用通常的CSS链接方式,会使页面每次载入时都需要重新从服务器请求,导致效率很低,那么可以通过headLoader.js加载字体,使字体包加载一次后便缓存下来,后续使用字体可以快速从缓存中获取:


let loader=new headLoader();
//字体包路径为"/font/elf_round.woff"
loader.dataFont=["/font/elf_round.woff"];
//加载后立即应用当前页面
loader.preload=0;
//缓存生命周期为7*24小时
loader.lifeCycle=7*24;
await loader.load();
//在页面中直接插入样式标签,也可以在CSS中定义,字体名称就是字体包文件名
let fontStyle=document.createElement("style");
fontStyle.setAttribute("type","text/css");
fontStyle.innerHTML=`*{font-family:elf_round, system, sans-serif;}`;
document.head.appendChild(fontStyle);
          

同站所有页面(重复)使用该方法加载该字体时仅从缓存中读取,而不会有额外的网络请求。

加载并缓存图片

headLoader可以将加载过的图片实时缓存,使网站的所有页面再次使用相同资源时,无需再次从服务器下载便可迅速载入。

1、html中定义

 <img data-file="/images/831dda91e69b229b.png">
 <img data-file="/images/9317e2bcce0b6579.png">
          

2、javascript代码

直接使用封装好的函数方法asyncImages,函数包括两个参数。


let thisLoader=new headLoader();
//无需thisLoader.load();
//asyncImages的第一个参数默认值为[7*24,48],表示缓存生命周期,即每周一检查更新,
//asyncImages的第二个参数默认10,为避免一次性加载图片过多返回高并发错误,函数自动分批加载,该值限制每批加载的图片最大个数。
thisLoader.asyncImages(7*24,10);
          

同站所有页面(重复)使用该方法加载该图片时仅从缓存中读取,而不会有额外的网络请求。

加载并缓存其它

headLoader不仅可以加载缓存JS、CSS文档,还支持更多的类型的文件,例如HTML、SVG等。

支持的文本文件类型有:"js","css","svg","text","xml","json","html","htm"等。

支持二进制文件类型但不限于这些类型:"jpg","png","woff"等。

let thisLoader=new headLoader();
let files;
//读取一个文件,第一次从网络地址读取,第二次从indexedDB中读取,如果数据过期,会自动更新。
files=await thisLoader.loadFile("/button.svg");
//loadFile返回的是Map对象,使用get方法获取值
console.log(files.get("/button.svg").value);
//同理缓存JS并返回所有文件代码
files=await thisLoader.loadJs(["/default.js","/button.js"]);
//同理缓存CSS并返回所有文件代码
files=await thisLoader.loadCss(["/index.css","/button.css"]);
//缓存并读取其它类型文件
files=await thisLoader.loadFile(["/index.html","/button.svg","/a.jpg"]);
//从files结果中检索文件代码(Map使用get方法)
console.log(files.get("/index.html").value);
console.log(files.get("/button.svg").value);
//或者使用db.getValue方法获取文件代码
console.log(await thisLoader.db.getValue("/button.svg"));
//db.getBase64方法可返回图片的base64编码(需要先使用loadFile加载)
console.log(await thisLoader.db.getBase64("/a.jpg"));
          

同站所有页面(重复)使用该方法加载该资源时仅从缓存中读取,而不会有额外的网络请求。

跨页缓存增删改查

headLoader在实例化后生成一个缓存方法的API,可实现多页面缓存共享,同一站点下不同页面可以随意存取。

例如两个不同页面,a.html和b.html,那么通过如下方法可以使两个页面像同一个页面一样的使用缓存:


//a.html和b.html的JS程序需要先各自实例化一个headLoader
let loader=new headLoader();
//定义数据存储的生命周期
loader.lifeCycle=[24,6];//数据有效期为24小时,每次延迟6小时。默认为【24,0],简写为24。
//无需初始化,实例化后即可使用
//在任意一个页面增加或修改缓存使用命令:loader.db.setValue(key,value)
await loader.db.setValue("names",["张三","李四","王五"]);
//在任意任一个页面查询缓存:loader.db.getValue(key)
let names=await loader.db.getValue("names");
console.log(names);//["张三","李四","王五"] 或 false
//在任意任一个页面删除缓存:loader.db.deleteItem(key)
await loader.db.deleteItem("names");
//{success: true, key: 'names', message: '数据删除成功: names'}
          

由于缓存仓库使用indexedDB,因此容量不受限制,您可用它应用大数据的缓存共享及管理。

localStorage API

headLoader提供了类似window.localStorage的同步API,支持存储任意类型的数据(数组、对象等),数据存储在indexedDB的sys表中,容量不受限制,并且严格遵守lifeCycle生命周期管理。

使用示例(同步方法,无需await):


// 实例化(lifeCycle=24*9999 表示数据几乎永不过期)
const hl = new headLoader({"lifeCycle": 24*9999});

// 同步存储数据(支持任意类型:数组、对象等)
hl.localStorage.setItem("key", [1,2,3]);

// 同步获取数据(立即返回)
const data = hl.localStorage.getItem("key"); // 返回 [1,2,3]

// 判断键是否存在且有效
hl.localStorage.has("key"); // 返回 true

// 同步删除数据
hl.localStorage.removeItem("key");

// 数据过期后返回 false
// 例如 lifeCycle=24 表示数据24小时后过期
const hl2 = new headLoader({"lifeCycle": 24});
hl2.localStorage.setItem("tempData", "24小时后过期");
// 24小时后:
hl2.localStorage.getItem("tempData"); // 返回 false
          

实际应用一:缓存服务器接口数据(减少网络请求)

以下示例展示如何使用 localStorage API 缓存服务器接口数据,避免重复请求:


// 实例化,接口数据缓存1小时
const apiCache = new headLoader({"lifeCycle": 1});

/**
 * 获取用户信息的函数
 * 优先从缓存读取,缓存过期或不存在时从服务器获取
 */
async function getUserInfo(userId) {
  const cacheKey = `userInfo_${userId}`;
  
  // 尝试从缓存获取数据
  const cachedData = apiCache.localStorage.getItem(cacheKey);
  
  if (cachedData !== false) {
    // 缓存命中,直接返回
    console.log('✅ 从缓存获取用户信息');
    return cachedData;
  }
  
  // 缓存未命中或已过期,从服务器获取
  console.log('🔄 从服务器获取用户信息');
  try {
    const response = await fetch(`/api/user/${userId}`);
    const userData = await response.json();
    
    // 存入缓存(1小时后过期)
    apiCache.localStorage.setItem(cacheKey, userData);
    
    return userData;
  } catch (error) {
    console.error('获取用户信息失败:', error);
    return null;
  }
}

// 使用示例
const user = await getUserInfo(123);
console.log(user); // {id:123, name:"张三", ...}

// 1小时内再次调用,直接从缓存获取
const userAgain = await getUserInfo(123); // ✅ 从缓存获取
          

实际应用:缓存列表数据(分页场景)


// 实例化,列表数据缓存30分钟
const listCache = new headLoader({"lifeCycle": 0.5});

/**
 * 获取文章列表
 * 缓存30分钟,避免频繁请求服务器
 */
async function getArticleList(page, pageSize) {
  const cacheKey = `articleList_${page}_${pageSize}`;
  
  // 尝试从缓存获取
  const cachedList = listCache.localStorage.getItem(cacheKey);
  
  if (cachedList !== false) {
    console.log(`✅ 第${page}页文章列表从缓存获取`);
    return cachedList;
  }
  
  // 从服务器获取
  console.log(`🔄 第${page}页文章列表从服务器获取`);
  try {
    const response = await fetch(`/api/articles?page=${page}&pageSize=${pageSize}`);
    const listData = await response.json();
    
    // 存入缓存(30分钟后过期)
    listCache.localStorage.setItem(cacheKey, listData);
    
    return listData;
  } catch (error) {
    console.error('获取文章列表失败:', error);
    return [];
  }
}

// 使用示例
const page1 = await getArticleList(1, 20); // 🔄 从服务器获取
const page1Again = await getArticleList(1, 20); // ✅ 从缓存获取
          

实际应用:跨页面共享数据(iframe场景)


// 顶级页面设置共享数据
const topLoader = new headLoader({"lifeCycle": 24});
topLoader.localStorage.setItem("sharedConfig", {
  theme: "dark",
  language: "zh-CN",
  version: "3.1.1"
});

// 同域 iframe 子页面直接读取(同步获取)
const iframeLoader = new headLoader();
const config = iframeLoader.localStorage.getItem("sharedConfig");
console.log(config.theme); // "dark"
console.log(config.language); // "zh-CN"

// 子页面修改共享数据
config.theme = "light";
iframeLoader.localStorage.setItem("sharedConfig", config);

// 顶级页面立即感知变化
console.log(topLoader.localStorage.getItem("sharedConfig").theme); // "light"
          

localStorage API 方法说明:

方法参数返回值
setItem(key, value)key: 键名
value: 任意类型值
true
getItem(key)key: 键名存储的值;不存在或已过期返回 false
has(key)key: 键名true/false
removeItem(key)key: 键名true

相比原生localStorage的优势:

  • 支持存储任意类型的数据(数组、对象等),无需JSON序列化
  • 存储容量不受限制(基于indexedDB)
  • 跨页面共享(同域下所有页面可访问,包括iframe)
  • 严格遵守lifeCycle生命周期管理(不分线上线下环境)
  • 同步API,使用简单直观,无需await
  • 适合缓存接口数据、配置信息、用户状态等
进阶

让headLoader.js只加载一个调度文件,仅通过修改调度文件实现整个站点所有页面的资源调配。

在所有的HTML页面插入相同的javascript标签,使其加载dispatch.js

<script type="text/javascript" data-dir="/" data-js="7c95b8b4e1b379bb" src="/87ce85eb5c1d99f3.js"></script>

dispatch.js程序,您可以根据需要修改使用:

(function(_g){
  /**
   *此部分为配置项代码,可根据项目需要修改
  */
  //基础CSS,所有页面都用
  _g.baseCss=['elficons','dracula','animate'];
  //基础JS,所有页面都用
  _g.baseJs=['libs/jquery','libs/jquery.cookie','libs/highlight'];
  //基础字体文件,所有页面都用
  _g.dataFont=["/font/elfRound/elf_round.woff"]
  //明确URL路径所用的资源
  _g.pathSource={
    "/map/":{
      dataCss:[..._g.baseCss,'_css'],
      dataJs:[..._g.baseJs,'_js'],
      dataFont:[..._g.dataFont]
    },
    "/icon/":{
      dataCss:[..._g.baseCss,'_css'],
      dataJs:[..._g.baseJs,'libs/clipboard','_js','utils/pageInit'],
      dataFont:[..._g.dataFont]
    },
    "/news/*":{
      dataCss:[..._g.baseCss,'_css'],
      dataJs:[..._g.baseJs,'libs/fuse','_js'],
      dataFont:[..._g.dataFont]
    },
    "*":{
      dataCss:[..._g.baseCss,'_css'],
      dataJs:[..._g.baseJs,'_js','utils/pageInit'],
      dataFont:[..._g.dataFont]
    }
  };
  /**
   *以下部分为固定的业务执行代码,不必修改
  */
  let getOption=function(_path){
    let path=_path.replace(/(\/.*)((\.html)|(index\.html))(.*)$/,"$1$5");
    let option={};
    let paths=Object.keys(_global.pathSource);
    let thisRegexp;
    let selfJsCss=_index=>_index.replace(/^\//,"").replace(/\/$/,'/index');
    for(let i=0; i<paths.length; i++){
      thisRegexp=new RegExp(`^${paths[i].replace('*','.*')}$`);
      if(thisRegexp.test(path)){
        option.dataJs=_global.pathSource[paths[i]].dataJs.map(_v=>_v==="_js" ? `${selfJsCss(path)}` : _v);
        option.dataCss=_global.pathSource[paths[i]].dataCss.map(_v=>_v==="_css" ? `${selfJsCss(path)}` : _v);
        option.dataFont=_global.pathSource[paths[i]].dataFont
        break;
      }
    }
    option.dataDir="/media/";
    option.callback=false;
    return option;
  };
  let thisOption=getOption(window===window.top ? window.location.pathname : window.frameElement.getAttribute("src") || window.frameElement["pathname"] || "");
  let loader=new headLoader(thisOption);
  //构造函数会自动加载资源,无需手动调用load()
})((window.location.origin==="null" || window.location.origin===window.top.location.origin) ? window.top : window);
            
注意事项
  • 由于本插件需要浏览器的IndexedDB功能,所以必须使用现代浏览器,例如:Chrome、Edge等;
  • 网站新版本上线一定严格按照数据的生命周期来完成,具体查看生命周期的计算方法;
  • 使用javascript语句数定义生命周期时,如果lifeCycle为数组,例如[168,48],则生命周期为168小时,延迟时间为48小时;
  • javascript标签的"data-css"属性定义css模块,多个css以逗号分割,headLoader会依次加载,不需要指定文件的扩展名称,"data-js"同理;
  • 标签属性定义法与命令行语句法中的属性名称分别如下一一对应: data-dir 相当于 dataDir data-css 相当于 dataCss data-js 相当于 dataJs;
  • css模块在"dataDir"路径下的"css"目录中,js模块在"dataDir"路径下的"js"目录中;
  • 命令行语句法可以定义回调函数,标签属性定义法不支持定义回调函数;
  • 当data-css包含"_css"模块时,代表headLoader自动加载页面css,例如当页面为127.0.0.1/index/index.html,则对应的css为127.0.0.1/css/index/index.css;
  • 当data-js包含"_js"模块时,代表headLoader自动加载页面js,例如当页面为127.0.0.1/index/index.html,则对应的js为127.0.0.1/js/index/index.js;
  • 当需要给加载的css或js标签添加属性时,可以用"_js|属性名=属性值|属性名=属性值|..."的形式实现,例如loader.dataJs=['_js|id=abc'];
  • 如果是公有IP或者非localhost,所加载的文档会直接从浏览器数据库中并发读取,版本默认每24个小时更新一次;
  • 如果是私有IP或者localhost开发环境,每次刷新页面都会以队列形式重新加载资源,这样做是为了方便开发调试,由此加载速度较慢,请知晓;
  • localStorage API 严格遵守 lifeCycle 生命周期,不分线上线下环境;
  • 当模块为完整的http地址时,例如loader.dataJs=['http://dwz.cn/headLoader'],将直接创建标签并加载,不进行任何处理;
  • 如果请求的URL发生404等异常错误时仍然返回数据包,目的是不会中断后续操作,数据包中的exception不为false时表示异常。例如:
    {
      "key": "/a/b.html",//这是一个不存在的网址
      "value": "",
      "exception": {
        "code": 404,
        "detail": "Error-404 ! 该资源找不到了。"
      },
      "version": 0,
      "etag": ""
    }
代码下载

https://github.com/baiyukey/headLoader

*代码仅供学习参考,并不定期更新版本,对于不同版本造成的任何问题,作者不承担任何法律责任,特此声明!

责任声明
  • 个人用户免费使用,捐赠请扫页面左栏下方的二维码,您的支持是对知识产权最大的尊重;
  • 营利机构,政府部门或者商业用户,您需要联系作者(baiyukey@qq.com)申请一个授权(*推广期酌情免费授权)
  • 作者保留一切法律权力,并对于侵权或者非法使用行为,有权追究一切法律责任;
  • UI精灵目前的域名仅有uielf.cn,而且暂未和任何第三方合作,对于冒名合作开发的机构作者保留追究其法律责任的权利。
关于我
我是一名网站全栈工程师,毕业于中央美院,江湖道义称一声宇哥,追求网站技术和美术设计20余载,自由职业。
UI精灵网站及技术成果全部由我研发,如果想拥有和我一样的网站,或者需要我的技术支持,欢迎与我洽谈合作。点此发送邮件
如果我的成果能够帮您节省宝贵的时间。不妨点击我的头像请我喝杯咖啡。或者推荐此网站给你的朋友或同事。