如何刷新客户端 INLINE javascript
How to refresh client INLINE javascript
使用外部 js 文件时,浏览器可能会被强制重新加载文件。参见 here。
最近,我发现 INLINE 脚本也被缓存了,至少在 Chrome 版本 80.0.3987.132 中是这样,
片段示例:
<html>
<head>
<script>alert("I am cached!");</script>
</head>
<body>
<script>alert("Me too!");</script>
</body>
</html>
刷新内联脚本的方法是什么?
更新 1:我不得不提到返回内容的网络服务器使用的是 HTTP 2.0
更新 2:一个可行的解决方案 是将辅助脚本作为基础,当页面加载时通过 ajax 获取 "real" 脚本内容或者 websocket 然后像这样将它附加到头部:
function addScript(content){
let s = document.createElement('script');
s.innerHTML = content;
document.head.appendChild(s);
}
这可以完成工作,但它不是最佳的,因为它需要比必要更多的请求。
更新 3:从后端发送的 Headers 似乎都不起作用,使用这些 headers:
Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1.
Header().Set("Pragma", "no-cache") // HTTP 1.0.
Header().Set("Expires", "0") // Proxies.
更新 4:根据 Jinxmcg 的回答,文档 https://v8.dev/blog/code-caching-for-devs Don’t change URLs
提到:
we may one day decide to associate caches with the source text rather than source URL, and this advice will no longer be valid.
可能那一天已经到来,并且也适用于内联脚本。
谢谢大家的参与
最终解决方案(至少在我的情况下有效):
1 后端 headers:
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate, max-age=0") // HTTP 1.1.
w.Header().Set("Pragma", "no-cache") // HTTP 1.0.
w.Header().Set("Expires", "0") // Proxies.
2 HTML、JS 和 CSS 中的随机字符串,示例:
<html>
<head>
<style>
--cache-color: #8528cc; //Random hex color generated by backend
</style>
<script>
console.log("<?php echo date(); ?>");
alert("I am cached!");
</script>
</head>
<body>
<div>Hidden DIV with a random value: <?php echo date(); ?></div>
<script>
console.log("<?php echo date(); ?>");
alert("Me too!");
</script>
</body>
</html>
我认为浏览器仅在为后续调用打开页面时才缓存内联 javascript session 并且在您关闭或刷新页面后不会保留它。
但是,这意味着浏览器在您的情况下从其缓存中获取 HTML(包括 JS)。因此,您可以尝试发送一些 headers 以及您的页面,强制浏览器不使用它的缓存 HTML 副本并使用新的 html+js.
为了测试它是否是 HTML 缓存或 "inline JS" 缓存问题,使您的 html 动态更改并确认它在刷新时更改但内联 JS 执行才不是。
您可以在此处找到有关 js 缓存的更多详细信息:https://v8.dev/blog/code-caching-for-devs
使用 document.createElement('script')
到 "refresh" 您的脚本是不好的解决方案。可能是您的缓存出了问题。
你试过了吗
Cache-Control: "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
?
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
如果您使用代理,请查看 proxy-revalidate。
调试时,您可以尝试在 Google Chrome 中尝试 shift + F5 或按住 shift 的同时按下重新加载按钮以强制完全刷新。 (如果您更改了脚本)
考虑为您的网页使用 max-age 的 Cache-Control 指令。
通常,max-age 可能会设置为相对较长的时间(以秒为单位)。这样做是为了通过让客户端在刷新缓存文件之前频繁重用缓存文件来提高性能。
在发布您希望客户端立即刷新的更改之前,将 max-age 值降低到零或几秒。然后,等待原始 max-age 持续时间到期,以便使用新的 max-age 值更新所有活动客户端。
在此等待期过后,推送文件更新并恢复到原始且更长的 max-age 值。
此序列将强制客户端刷新所需的文件更改。
使用外部 js 文件时,浏览器可能会被强制重新加载文件。参见 here。
最近,我发现 INLINE 脚本也被缓存了,至少在 Chrome 版本 80.0.3987.132 中是这样, 片段示例:
<html>
<head>
<script>alert("I am cached!");</script>
</head>
<body>
<script>alert("Me too!");</script>
</body>
</html>
刷新内联脚本的方法是什么?
更新 1:我不得不提到返回内容的网络服务器使用的是 HTTP 2.0
更新 2:一个可行的解决方案 是将辅助脚本作为基础,当页面加载时通过 ajax 获取 "real" 脚本内容或者 websocket 然后像这样将它附加到头部:
function addScript(content){
let s = document.createElement('script');
s.innerHTML = content;
document.head.appendChild(s);
}
这可以完成工作,但它不是最佳的,因为它需要比必要更多的请求。
更新 3:从后端发送的 Headers 似乎都不起作用,使用这些 headers:
Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1.
Header().Set("Pragma", "no-cache") // HTTP 1.0.
Header().Set("Expires", "0") // Proxies.
更新 4:根据 Jinxmcg 的回答,文档 https://v8.dev/blog/code-caching-for-devs Don’t change URLs
提到:
we may one day decide to associate caches with the source text rather than source URL, and this advice will no longer be valid.
可能那一天已经到来,并且也适用于内联脚本。
谢谢大家的参与
最终解决方案(至少在我的情况下有效):
1 后端 headers:
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate, max-age=0") // HTTP 1.1.
w.Header().Set("Pragma", "no-cache") // HTTP 1.0.
w.Header().Set("Expires", "0") // Proxies.
2 HTML、JS 和 CSS 中的随机字符串,示例:
<html>
<head>
<style>
--cache-color: #8528cc; //Random hex color generated by backend
</style>
<script>
console.log("<?php echo date(); ?>");
alert("I am cached!");
</script>
</head>
<body>
<div>Hidden DIV with a random value: <?php echo date(); ?></div>
<script>
console.log("<?php echo date(); ?>");
alert("Me too!");
</script>
</body>
</html>
我认为浏览器仅在为后续调用打开页面时才缓存内联 javascript session 并且在您关闭或刷新页面后不会保留它。
但是,这意味着浏览器在您的情况下从其缓存中获取 HTML(包括 JS)。因此,您可以尝试发送一些 headers 以及您的页面,强制浏览器不使用它的缓存 HTML 副本并使用新的 html+js.
为了测试它是否是 HTML 缓存或 "inline JS" 缓存问题,使您的 html 动态更改并确认它在刷新时更改但内联 JS 执行才不是。
您可以在此处找到有关 js 缓存的更多详细信息:https://v8.dev/blog/code-caching-for-devs
使用 document.createElement('script')
到 "refresh" 您的脚本是不好的解决方案。可能是您的缓存出了问题。
你试过了吗
Cache-Control: "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
?
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
如果您使用代理,请查看 proxy-revalidate。
调试时,您可以尝试在 Google Chrome 中尝试 shift + F5 或按住 shift 的同时按下重新加载按钮以强制完全刷新。 (如果您更改了脚本)
考虑为您的网页使用 max-age 的 Cache-Control 指令。
通常,max-age 可能会设置为相对较长的时间(以秒为单位)。这样做是为了通过让客户端在刷新缓存文件之前频繁重用缓存文件来提高性能。
在发布您希望客户端立即刷新的更改之前,将 max-age 值降低到零或几秒。然后,等待原始 max-age 持续时间到期,以便使用新的 max-age 值更新所有活动客户端。
在此等待期过后,推送文件更新并恢复到原始且更长的 max-age 值。
此序列将强制客户端刷新所需的文件更改。