文章原发于个人主页:
https://www.bas369.com/more/learning_notes/2020/07/21/使用JavaScript记录cookie更新浏览器html缓存文件/
欢迎大家访问我的个人导航网站并且设置为主页:
巴士369,伴您到永久!https://www.bas369.com
1. 原理说明
1.利用浏览器响应 html 文件请求的响应头信息 last-modified
(文件最后更新时间) 和 ETag
来判断 html 文件是否更新;
2.实际使用中,因为无法获取 ETag
信息,所以实际仅仅利用了请求头的 last-modified
信息;
2. 参考文档
- Web 开发技术请参见 HTTP请参见 HTTP HeadersLast-Modified:https://developer.mozilla.org...
- Web 开发技术请参见 HTTP请参见 HTTP HeadersETag:https://developer.mozilla.org...
- HTTP的请求头标签 If-Modified-Since:https://www.cnblogs.com/zh200...
- 你知道 http 响应头中的 ETag 是如何生成的吗:https://segmentfault.com/a/11...
3. 代码实现
// 本代码依赖于 jQuery ;
// jQuery(document).ready(function(){}); 意义为在 DOM 加载完毕后执行了ready()方法,简写为 jQuery(function(){});
$( document ).ready( function ( ) {
// 定义一个函数,用来记录 cookie ;
function HomePageSetCookie_For_CheckHomePageHtmlFileIsChange_For_ReloadHomePageHtmlFile ( ) {
// 判断是否为网站的首页;
if ( window.location.pathname == "/index.html" ) {
// 建立 xhr 请求;
var xhr = new XMLHttpRequest();
if( !xhr ){
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// 参数 HEAD 需要配合 nginx 的配置文件 if ($request_method !~* GET|POST|HEAD) { return 444; } ;否则无法获取回应;
xhr.open( "HEAD" , window.location.href + "?timestamp=" + Date.now() , true ) ;
xhr.onreadystatechange=function(){
// xhr 请求成功;
if( xhr.readyState == 4 && xhr.status == 200 ){
// 定义函数,删除特殊字符串;
function DeleteTitle_SpecialString( LastModified ) {
LastModified = LastModified.replace(/\s+/g,'') ;
LastModified = ( ( LastModified.replace( /,/g , '' ) ).replace( /;/g , '' ) ).replace( /:/g , '' ) ;
return LastModified ;
}
// 提取 xhr 响应头的 last-modified ;
var ResponseHeaders_LastModified = xhr.getResponseHeader( "last-modified" ) ;
ResponseHeaders_LastModified = DeleteTitle_SpecialString( ResponseHeaders_LastModified ) ;
// 判断是否已经存在 cookie 记录,正则代码([^;]+)匹配非分号字符; (?:;|$)匹配分号或行尾 ;_HasIndexHtml 表示网站首页的 window.location.pathname 包含 "/index.html" 字符串 ;
if ( document.cookie.match(/HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml=([^;]+)(;|$)/) != null ) {
// 读取 cookie 记录;
var Array_LastModified_HasIndexHtml = document.cookie.match(/HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml=([^;]+)(;|$)/);
var Cookie_LastModified_HasIndexHtml = Array_LastModified_HasIndexHtml[ 0 ].substring( Array_LastModified_HasIndexHtml[ 0 ].indexOf( "=" ) + 1 , Array_LastModified_HasIndexHtml[ 0 ].length ) ;
Cookie_LastModified_HasIndexHtml = DeleteTitle_SpecialString( Cookie_LastModified_HasIndexHtml ) ;
// 根据 last-modified 判断 html 文件已经修改;
if ( Cookie_LastModified_HasIndexHtml != ( ResponseHeaders_LastModified + "_HasIndexHtml" ) ) {
// 更新 cookie 记录;
var cookie_path = "/" ;
document.cookie = "HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml="+ResponseHeaders_LastModified+"_HasIndexHtml; expires=Fri, 31 Dec 9999 23:59:59 GMT; " + ( window.location.host == "" ? "" : "domain=" + ( ( window.location.hostname ).indexOf( "www." ) != -1 ? ( window.location.hostname ).substring( 3 , ( window.location.hostname ).length ) : "." + window.location.hostname ) ) + "; path=" + cookie_path + "; SameSite=none; Secure=true" ;
// 刷新网站的首页,更新 html 文件缓存;注意:要先更新 cookie 记录,后执行 window.location.reload( ); 否则会导致页面刷新的死循环 ;
window.location.reload( );
// 重新赋值 variable_For_MultiTabPageHtmlReLoad_HasIndexHtml 变量;
// 用于浏览器同时打开多个标签页流量网站首页的时候,更新全部标签页的 html 文件缓存;
window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = document.cookie.match(/HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml=([^;]+)(;|$)/);
window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].substring( window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].indexOf( "=" ) + 1 , window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].length ) ;
window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = DeleteTitle_SpecialString( window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml ) ;
}
else { // if ( Cookie_LastModified_HasIndexHtml == ( ResponseHeaders_LastModified + "_HasIndexHtml" ) ) {
// 更新 cookie 记录;
var cookie_path = "/" ;
document.cookie = "HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml="+ResponseHeaders_LastModified+"_HasIndexHtml; expires=Fri, 31 Dec 9999 23:59:59 GMT; " + ( window.location.host == "" ? "" : "domain=" + ( ( window.location.hostname ).indexOf( "www." ) != -1 ? ( window.location.hostname ).substring( 3 , ( window.location.hostname ).length ) : "." + window.location.hostname ) ) + "; path=" + cookie_path + "; SameSite=none; Secure=true" ;
// 通过 variable_For_MultiTabPageHtmlReLoad_HasIndexHtml 变量,判断是否其他的标签页已经更新了 html 文件的同时,更新了 cookie 记录 ;
// 其他标签页虽然可以更新 cookie ,但是不能更新 本标签页的 window. 对象属性;
if ( $.type( window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml ) == "undefined" ) {
// 定义一个变量,用来解决在 两个 标签页中 同时打开首页的时候:其中一个首页更新了 html 文件,并且重写了 cookie 记录;导致另外一个首页更新 html 文件失败的问题;
// 因为第一个 首页更新 html 文件的时候,已经将 cookie 记录重写为最新的值,此时第二个标签页比对 ResponseHeaders_LastModified 与 cookie 记录,发现是相同的,就不会去更新 html 页面;
// 此处定义一个变量就是为了解决此问题,先将 旧的 cookie 记录挂载到 window. 的全局变量上;
// 如果发现 ResponseHeaders_LastModified 与 cookie 记录相同,那么就再比对最新的 cookie 记录(也就是最后的 ResponseHeaders_LastModified ) 与 全局变量 window. 上挂载的 cookie 旧记录是否相同;因为其他标签页虽然可以更新 cookie ,但是不能更新 本标签页的 window. 对象属性;
// 不相同的话,说明其他的 html 文件已经更新了缓存,那么本标签页就重新载入 html 缓存文件;
var variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = document.cookie.match(/HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml=([^;]+)(;|$)/);
variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].substring( variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].indexOf( "=" ) + 1 , variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].length ) ;
variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = DeleteTitle_SpecialString( variable_For_MultiTabPageHtmlReLoad_HasIndexHtml ) ;
window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = variable_For_MultiTabPageHtmlReLoad_HasIndexHtml ;
}
else if ( window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml != ( ResponseHeaders_LastModified + "_HasIndexHtml" ) ) {
// 刷新网站的首页,更新 html 文件缓存;
window.location.reload( );
// 重新赋值 variable_For_MultiTabPageHtmlReLoad_HasIndexHtml 变量;
window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = document.cookie.match(/HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml=([^;]+)(;|$)/);
window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].substring( window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].indexOf( "=" ) + 1 , window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].length ) ;
window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = DeleteTitle_SpecialString( window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml ) ;
}
}
}
else { // == null ,没有 cookie 记录;
var cookie_path = "/" ;
document.cookie = "HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml="+ResponseHeaders_LastModified+"_HasIndexHtml; expires=Fri, 31 Dec 9999 23:59:59 GMT; " + ( window.location.host == "" ? "" : "domain=" + ( ( window.location.hostname ).indexOf( "www." ) != -1 ? ( window.location.hostname ).substring( 3 , ( window.location.hostname ).length ) : "." + window.location.hostname ) ) + "; path=" + cookie_path + "; SameSite=none; Secure=true" ;
// 定义一个变量,用来解决在 两个 标签页中 同时打开首页的时候:其中一个首页更新了 html 文件,并且重写了 cookie 记录;导致另外一个首页更新 html 文件失败的问题;
// 因为第一个 首页更新 html 文件的时候,已经将 cookie 记录重写为最新的值,此时第二个标签页比对 ResponseHeaders_LastModified 与 cookie 记录,发现是相同的,就不会去更新 html 页面;
// 此处定义一个变量就是为了解决此问题,先将 旧的 cookie 记录挂载到 window. 的全局变量上;
// 如果发现 ResponseHeaders_LastModified 与 cookie 记录相同,那么就再比对最新的 cookie 记录(也就是最后的 ResponseHeaders_LastModified ) 与 全局变量 window. 上挂载的 cookie 旧记录是否相同;因为其他标签页虽然可以更新 cookie ,但是不能更新 本标签页的 window. 对象属性;
// 不相同的话,说明其他的 html 文件已经更新了缓存,那么本标签页就重新载入 html 缓存文件;
var variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = document.cookie.match(/HomePageSetCookie_ResponseHeaders_LastModified_HasIndexHtml=([^;]+)(;|$)/);
variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].substring( variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].indexOf( "=" ) + 1 , variable_For_MultiTabPageHtmlReLoad_HasIndexHtml[ 0 ].length ) ;
variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = DeleteTitle_SpecialString( variable_For_MultiTabPageHtmlReLoad_HasIndexHtml ) ;
window.variable_For_MultiTabPageHtmlReLoad_HasIndexHtml = variable_For_MultiTabPageHtmlReLoad_HasIndexHtml ;
}
} // if( xhr.readyState == 4 && xhr.status == 200 ) 语句结束
} // xhr.onreadystatechange=function() 结束
xhr.send(null);
}
}
// 页面打开的时候,立即执行一次函数,判断是否更新 html 文件;
setTimeout ( function ( ) {
HomePageSetCookie_For_CheckHomePageHtmlFileIsChange_For_ReloadHomePageHtmlFile ( ) ;
} , 1 ) ;
// 每隔 15 分钟,定时检查 html 文件是否需要更新缓存;
setInterval ( function ( ) {
HomePageSetCookie_For_CheckHomePageHtmlFileIsChange_For_ReloadHomePageHtmlFile ( ) ;
} , 900000 ) ;
} ) ; // $(document).ready(function(){