一天,客服反饋,說用戶購買某一產品時,提交訂單失敗,并發來用戶的接口提示。我一看,這不是昨天晚上升級之前的頁面嗎?昨天驗證過沒有問題呢。為什么用戶看到的是老的頁面?應該是緩存的原因。回客服,讓客戶多刷新下頁面,重新購買就可以了。
問題倒是解決了,但是客戶體驗非常不好,不能讓老客戶進來都重多次刷新頁面吧!有沒有方法可以解jsp、html或者js的緩存問題呢?
前言
解決前端緩存問題,就需要頁面加載的時候,不去讀取瀏覽器的緩存,而是從Web服務器上重新獲取頁面。
一、方法講解
服務端方法
response.setHeader("Pragma","No-cache"); response.setHeader("Cache-Control","no-cache"); response.setDateHeader("Expires", -10);
Pragma頭域用來包含實現特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1協議中,它的含義和Cache- Control:no-cache相同。
Cache -Control指定請求和響應遵循的緩存機制,no-cache指示請求或響應消息不能緩存。
Expires 響應頭包含日期/時間, 即在此時候之后,響應過期,無效的日期,比如 -10, 代表著過去的日期,即該資源已經過期。
客戶端方法
meta 是用來在HTML文檔中模擬HTTP協議的響應頭報文。meta 標簽用于網頁的<head>與</head>中,meta 標簽的用處很多。meta 的屬性有兩種:name和http-equiv。name屬性主要用于描述網頁,對應于content(網頁內容),以便于搜索引擎機器人查找、分類(目 前幾乎所有的搜索引擎都使用網上機器人自動查找meta值來給網頁分類)。這其中最重要的是description(站點在搜索引擎上的描述)和 keywords(分類關鍵詞),所以應該給每頁加一個meta值。比較常用的有以下幾個:
name 屬性
1、<meta name="Generator" contect="">用以說明生成工具(如Microsoft FrontPage 4.0)等;
2、<meta name="KEYWords" contect="">向搜索引擎說明你的網頁的關鍵詞;
3、<meta name="DEscription" contect="">告訴搜索引擎你的站點的主要內容;
4、<meta name="Author" contect="你的姓名">告訴搜索引擎你的站點的制作的作者;
5、<meta name="Robots" contect="all|none|index|noindex|follow|nofollow">
http-equiv屬性
1、<meta http-equiv="Content-Type" contect="text/html";charset=gb_2312-80"> 和 <meta http-equiv="Content-Language" contect="zh-CN">用以說明主頁制作所使用的文字以及語言;又如英文是ISO-8859-1字符集,還有BIG5、utf-8、 shift-Jis、Euc、Koi8-2等字符集;
2、<meta http-equiv="Refresh" contect="n;url=http://yourlink">定時讓網頁在指定的時間n內,跳轉到頁面http;//yourlink;
3、<meta http-equiv="Expires" contect="Mon,12 May 2001 00:20:00 GMT">可以用于設定網頁的到期時間,一旦過期則必須到服務器上重新調用。需要注意的是必須使用GMT時間格式;
4、<meta http-equiv="Pragma" contect="no-cache">是用于設定禁止瀏覽器從本地機的緩存中調閱頁面內容,設定后一旦離開網頁就無法從Cache中再調出;
5、<meta http-equiv="set-cookie" contect="Mon,12 May 2001 00:20:00 GMT">cookie設定,如果網頁過期,存盤的cookie將被刪除。需要注意的也是必須使用GMT時間格式;
6、<meta http-equiv="Pics-label" contect="">網頁等級評定,在IE的internet選項中有一項內容設置,可以防止瀏覽一些受限制的網站,而網站的限制級別就是通過meta屬性來設置的;
7、<meta http-equiv="windows-Target" contect="_top">強制頁面在當前窗口中以獨立頁面顯示,可以防止自己的網頁被別人當作一個frame頁調用;
8、<meta http-equiv="Page-Enter" contect="revealTrans(duration=10,transtion= 50)">和<meta http-equiv="Page-Exit" contect="revealTrans(duration=20,transtion =6)">設定進入和離開頁面時的特殊效果,這個功能即FrontPage中的“格式/網頁過渡”,不過所加的頁面不能夠是一個frame頁面。
二、Jsp、html緩存的解決
前端頁面處理方法
禁止客戶端緩存要在<head>中加入類似如下內容:
<meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0">
不設置超時時間
<% response.setHeader("Cache-Control","no-store"); response.setHeader("Pragrma","no-cache"); response.setDateHeader("Expires",0); %>
設置超時時間10分鐘
<% int minutes = 10; Date d = new Date(); String modDate = d.toGMTString(); String expDate = null; expDate = (new Date(d.getTime() + minutes * 60000)).toGMTString(); response.setHeader("Last-Modified", modDate); response.setHeader("Expires", expDate); response.setHeader("Cache-Control", "public"); // HTTP/1.1 response.setHeader("Pragma", "Pragma"); // HTTP/1.0 %>
后端處理方法
public class CacheJiejue extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); //指定該頁面不緩存 response.setDateHeader("Expires",-1); //IE游覽器支持的 //保證兼容性 response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragme", "no-cache"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
三、Js、css緩存的解決
Js或者css會被瀏覽器緩存下來,只有瀏覽器重啟后才會刪除,甚至重啟都不會刪除。這樣用戶可能看到的就是緩存的頁面效果。會照成生產問題。怎么解決呢?
方法一
在js或者css地址后面添加時間戳或者隨機數,這樣每次請求都是新的地址,可以騙過瀏覽器的緩存,每次去服務器獲取最新的代碼。但是每次都去請求服務器獲取新的代碼,會占用帶寬。
<link rel="stylesheet" href="/Resource/css/webapp_reset.css?s=<%=System.currentTimeMillis()%>"/> <script type="text/javascript" src="/Resource/js/mobiscroll.custom-2.16.1.min.js?s=<%=Math.random()%>" ></script>
方法二
可以添加版本號,每次修改的話在地址后面生成新的版本號,可以用系統時間作為當前更新的版本號。
<script type="text/javascript" src="/Resource/js/mobiscroll.custom-2.16.1.min.js?version=20190908" ></script>
搞定!!喜歡的朋友可以關注下~
最近寫博客真的是太痛苦了,倒不是寫博客本身,而是寫完之后往多個平臺發布的過程,一不注意就是十多分鐘往上的時間消耗。
為了解決這個問題,之前立項的“解決自媒體一鍵多平臺發布”項目必須得立刻著手完善了,爭取早日讓自己從發布這件事情上解脫出來專心寫文章。
【hxsfx的JavaScript庫】這個系列基本上是為“一鍵多平臺發布”項目打基礎用的。之所以把各個功能模塊拆分出來,是為了盡量讓小伙伴能夠復制即用(在兼容性方面,因為個人能力的原因,幾乎只會兼容Chrome瀏覽器)。
AJAX 是異步的 JavaScript 和 XML(Asynchronous JavaScript And XML),開發hxsfx.ajax庫的主要目的就是希望通過異步加載HTML,從而盡量避免直接在js中寫HTML來刷新頁面內容。
hxsfx.ajax這個庫與jquery的ajax功能基本一致,不過短時間內應該是寫不到人家那么完善的。哈哈~
各位小伙伴別問,為什么不用jquery的ajax而要自己再寫一個呢?
問就是,博主喜歡造輪子。開玩笑了~
其實原因是為了減少三方庫的依賴,達到對項目的全面掌控。
項目地址:https://github.com/hxsfx/hxsfx_web_tools
要自己開發一個ajax庫,需要借助Web API接口中的XMLHttpRequest(XHR)對象。
XMLHttpRequest(XHR)對象用于與服務器交互。通過 XMLHttpRequest 可以在不刷新頁面的情況下請求特定 URL,獲取數據。這允許網頁在不影響用戶操作的情況下,更新頁面的局部內容。
//hxsfx.js
(function () {
window.hxsfx = {};
})();
//ajax.js
(function () {
window.hxsfx.ajax = {
};
})();
//ajax.js
(function () {
window.hxsfx.ajax = {
loadHTML: function (ele, url) {
}
};
})();
//ajax.js
(function () {
window.hxsfx.ajax = {
loadHTML: function (ele, url) {
const httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url, true);
httpRequest.onreadystatechange = function () {
//為了讓代碼更健壯,使用try...catch來捕獲返回狀態判斷和處理HTML代碼的異常
try {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
//在這處理返回的HTML
}
}
else {
console.log("【ajax.get(" + url + ")請求出錯】");
}
}
}
catch (ex) {
console.log("【ajax.get(" + url + ")異常】" + ex.message);
}
};
httpRequest.send();
}
};
})();
//ajax.js
//時間戳用來解決加載頁面緩存的問題
var urlTimeStamp = "timeStamp=" + new Date().getTime();
url += ((url.indexOf('?') >= 0) ? "&" : "?") + urlTimeStamp;
//ajax.js
ele.innerHTML = httpRequest.responseText;
var scriptElements = ele.getElementsByTagName("script");
for (var i = 0; i < scriptElements.length; i++) {
var scriptElement = document.createElement("script");
scriptElement.setAttribute("type", "text/javascript");
var src = scriptElements[i].getAttribute("src");
if (src) {
//因為加載的src路徑是之前相對加載HTML頁面的,需要修改為當前頁面的引用路徑
src = url.substring(0, url.lastIndexOf('/') + 1) + src;
src += ((src.indexOf('?') >= 0) ? "&" : "?") + urlTimeStamp;
scriptElement.setAttribute("src", src);
}
var scriptContent = scriptElements[i].innerHTML;
if (scriptContent) {
scriptElement.innerHTML = scriptContent;
}
//用生成的script元素去替換html中的script標簽,以此來激活script代碼
ele.replaceChild(scriptElement, scriptElements[i]);
}
//ajax.js
(function () {
window.hxsfx.ajax = {
loadHTML: function (ele, url) {
//時間戳用來解決加載頁面緩存的問題
var urlTimeStamp = "timeStamp=" + new Date().getTime();
url += ((url.indexOf('?') >= 0) ? "&" : "?") + urlTimeStamp;
const httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url, true);
httpRequest.onreadystatechange = function () {
//為了讓代碼更健壯,使用try...catch來捕獲返回狀態判斷和處理HTML代碼的異常
try {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
ele.innerHTML = httpRequest.responseText;
var scriptElements = ele.getElementsByTagName("script");
for (var i = 0; i < scriptElements.length; i++) {
var scriptElement = document.createElement("script");
scriptElement.setAttribute("type", "text/javascript");
var src = scriptElements[i].getAttribute("src");
if (src) {
//因為加載的src路徑是之前相對加載HTML頁面的,需要修改為當前頁
src = url.substring(0, url.lastIndexOf('/') + 1) + src;
src += ((src.indexOf('?') >= 0) ? "&" : "?") + urlTimeStamp;
scriptElement.setAttribute("src", src);
}
var scriptContent = scriptElements[i].innerHTML;
if (scriptContent) {
scriptElement.innerHTML = scriptContent;
}
//用生成的script元素去替換html中的script標簽,以此來激活script代
ele.replaceChild(scriptElement, scriptElements[i]);
}
}
}
else {
console.log("【ajax.get(" + url + ")請求出錯】");
}
}
}
catch (ex) {
console.log("【ajax.get(" + url + ")異常】" + ex.message);
}
};
httpRequest.send();
}
};
})();
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>js庫測試</title>
<script src="Scripts/hxsfx/hxsfx.js"></script>
<script src="Scripts/hxsfx/ajax.js"></script>
<script>
window.onload = function () {
//調用ajax中的loadHTML方法
window.hxsfx.ajax.loadHTML(document.getElementById("ContentContainer"), "Views/test/testPage.html");
};
</script>
</head>
<body>
<div id="ContentContainer"></div>
</body>
</html>
<style>
div#TestPageContainer {
height: 300px;
width: 300px;
background-color: #F0F0F0;
}
</style>
<script src="../../Scripts/hxsfx/test/test.js"></script>
<script>
function updateBackgroundColor() {
try {
var backgroundColor = '#' + (Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0'));
document.getElementById("TestPageContainer").style.backgroundColor = backgroundColor;
}
catch (ex) {
console.log(ex.message);
}
}
</script>
<div id="TestPageContainer">
<button onclick="updateBackgroundColor()">更改背景色</button>
<button onclick="modifyPFontColor()">更改下面一句話的字體顏色</button>
<p id="P">這兒是一句話。</p>
</div>
以上內容只是hxsfx.ajax庫的開始,后續的內容更新小伙伴可以通過訪問Github項目地址進行獲取。
迎關注我的頭條號:Wooola,專注于Java、Golang、微服務架構,致力于每天分享原創文章、快樂編碼和開源技術。
最近發版前端項目,用戶經常反饋新添加功能在線上環境不好用,常出現新老頁面并存的狀況。經前端同事排查法發現,實際上只需要重新刷新一下頁面就沒事了。但是每次去通知用戶肯定不現實,所以需要對前端的js和css等文件采取一定的緩存失效的措施,強制瀏覽器重新去服務器獲取新的js代碼以及css文件。
樓主經過實際的項目情況反饋,總結以下兩點切實可行的辦法,分享給大家,希望對大家有幫助。
時間版本號
如果每次發布,針對修改過的js或者css文件路徑加上時間的版本號,一般以年月日拼寫。
<script type="text/javascript" src="lib/common.js?v=20190719"></script> <link rel="stylesheet" type="text/css" href="assets/css/ie/ie8.css?v=20190719" />
如果發生緊急情況,需要在一天當中對某些css或者js文件多次發版,可以把時間精確到時分秒。
目前樓主主推采用加版本號的方式,因為文件太多,只能做增量修改。好處是沒有做任何修改js或者css文件可以不用加版本號。
采用隨機數
document.write('<script src=\".lib/common.js?r=' + Math.random() + "\"" + '><\/script>');
一般不建議用隨機數的方式,因為每次刷新頁面,隨機數都會變化,那么瀏覽器認為一個新的url需要重新請求服務端獲取js或css文件,不會在使用瀏覽器本地緩存。同時占用網絡帶寬,影響服務器響應速度。
可以利用 gulp-rev或者webpack
entry: { main: './src/common.js', slove: './src/ie8.js' }, output: { filename: '[name].[hash].js', path: path.resolve(__dirname, 'dist') }
例如百度搜索首頁,就是利用hash給js和css文件重命名。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。