因爲 Cookie 能夠被用戶篡改,不是一個安全的選擇,因此利用 Session 來解決防止用戶篡改的需求。css
Session 是屬於服務器的一個哈希表。api
在使用時,先定義一個sessions
的哈希表,並生成一個隨機數當作當前用戶的sessionId
,使用隨機數是爲了安全,這樣用戶就沒法經過篡改獲得其餘用戶正確的sessionId
。接着將本應該放到 Cookie 裏的信息放到sessions[sessionId]
裏面,存放到服務器上,並將sessionId
經過Cookie
傳給瀏覽器。瀏覽器
代碼實現以下:緩存
let sessionId = Math.random() * 100000; //此處更改爲其餘隨機方式
sessions[sessionId] = { sign_in_email: email };
response.setHeader('Set-Cookie',`sessionId=${sessionId}`);
複製代碼
經過這樣的操做,瀏覽器並不直接獲得用戶信息,而是給一個sessionId
,服務器經過sessions
匹配瀏覽器附帶的sessionId
,獲得用戶信息。避免用戶經過篡改 Cookie 獲取其餘用戶的信息,並且sessionId
是隨機生成的,徹底沒有規律可循,也就沒法僞造其餘用戶的sessionId
。安全
//hash 就是將 Cookie 裏的信息對象化獲得的
let mySession = sessions[hash.sessionId];
let email;
if (mySession) {
email = mySession.sign_in_email;
}
複製代碼
這樣也能夠獲得當前用戶的信息,並且用戶還沒法僞形成其餘用戶。服務器
sessionId
基於 Cookie 實現的sessionId
經過 Cookie
發送給瀏覽器sessionId
sessionId
-用戶信息 的鍵值對哈希表(sessions)sessionId
就能夠獲得對應用戶的信息Session 太佔內存了,每個用戶都要存儲 (sessionId
- 用戶信息),並且不能回收,當用戶量很大時,對硬件性能要求特別高。網絡
LocalStorage 是存放在瀏覽器上的一個哈希表,且只能存放字符串(對於非字符串自動轉換成字符串,.toString()
)。session
瀏覽器有一個window.localstorage
的 api,以下所示:dom
由於 LocalStorage 的值不隨頁面的關閉、刷新等發生變化,因此能夠用來存儲某些不須要隨頁面刷新而發生變化的值,持久化存儲。性能
經常使用場景爲:記錄有沒有提示過用戶某信息(不能用來記錄密碼)
這是用來存儲 LocalStorage 數據的,用法以下
//語法
localStorage.setItem('key','value')
//實例
localStorage.setItem('name','yyzcl')
複製代碼
非字符串的 key
和 value
會被轉換成字符串的形式,能夠存 JSON。
localStorage.setItem('yyzcl',{age: '18'})
localStorage.setItem('yyzcl2',JSON.stringify({age: '18'}))
複製代碼
用來讀取 LocalStorage 裏面的數據,用法以下:
//語法
localStorage.getItem('key')
//實例
localStorage.getItem('yyzcl2')
複製代碼
用來刪除 LocalStorage 已經存儲的值,用法以下:
//語法
localStorage.removeItem('key')
//實例
localStorage.removeItem('yyzcl')
複製代碼
清空 LocalStorage 的值。
SessionStorage 與 LocalStorage 相似,也有 LocalStorage 那些 api等等特徵。可是,SessionStorage 在用戶關閉頁面(結束會話)時就會失效
當咱們刷新頁面時,若是要從新請求一遍相同的資源,那就太消耗網絡和時間了。那麼有沒有辦法讓 HTTP 在請求相同資源的時候,不通過網絡鏈接服務器,直接從內存或硬盤中讀取以前下載的資源呢?有這麼幾種方法能夠實現。
Cache-Control 通用消息頭被用於在 HTTP 請求和響應中經過指定指令來實現緩存機制。用法以下:
//語法
Cache-Control: max-age=<seconds> //實例 response.setHeader('Cache-Control', 'max-age=30'); 複製代碼
若是咱們給一個頁面的 JS 文件響應設置了 Cache-Control 後,那麼在30秒內重複請求這個 JS 文件的話,瀏覽器會阻止這個請求,轉而從內存或硬盤中讀取這個 JS 文件。
這是首次加載的狀況。
而且在響應體中會有一個 Cache-Control: max-age=30
的信息,以下圖所示。
當瀏覽器在30秒以內再次請求這個 JavaScript 文件時,會是以下情形。
從圖中能夠看到,當設置了 Cache-Control ,而且在有效時間以內重複請求同一個文件,處理時間爲 0ms,也就是說瀏覽器根本沒有向服務器發出請求,而是從內存中讀取請求的文件。
JS、CSS 文件的緩存時間通常設置成一個很大的值,好比一年。
那麼期間要更新 JS、CSS 文件怎麼辦?
這裏只須要更改下 JS、CSS 的請求 URL 便可,好比加一個查詢參數。效果以下:
Expires 也是用來控制緩存,與 Cache-Control 不同的是,Expires 響應頭包含日期/時間, 即在此時候以後,響應過時。無效的日期,好比 0, 表明着過去的日期,即該資源已通過期。用法以下:
//語法
Expires: <http-date> //實例 response.setHeader('Expires', 'Wen, 31 Jul 2018 15:55:10 GMT'); 複製代碼
在有效期以內,重複的請求也會被瀏覽器阻止,轉而從內存中讀取文件。
一樣的更改請求的 URL 便可在有效期內更新文件。
須要注意的是,Expires 返回的是服務器時間,而瀏覽器在進行時間判斷時是以本地時間爲基準的,若是本地時間與服務器時間相差過大,請求或許會出現 bug。好比將本地時間調整至有效期以後,那麼每次請求都發送給服務器,不會被瀏覽器阻止。
而且當 Expires 與 Cache-Control 同時設置時,Expires 會被忽略,只有 Cache-Control 起做用。
ETag HTTP 響應頭是資源的特定版本的標識符。這可讓緩存更高效,並節省帶寬,由於若是內容沒有改變,Web 服務器不須要發送完整的響應。而若是內容發生了變化,使用 ETag 有助於防止資源的同時更新相互覆蓋(「空中碰撞」)。
上面是 MDN 對 ETag 的介紹,通俗的來說,就是 ETag 記錄了請求的文件的版本號,瀏覽器在每次請求這個文件的時候,會帶上這個版本號(做爲 If-None-Match 字段的值),服務器若是發現文件版本號沒有發生變化,也就是文件沒有發生改變,那就不須要從新將文件發送給瀏覽器,讓瀏覽器在緩存中讀取以前下載的文件便可。
能夠利用 MD5 值做爲文件的版本號,由於即便一個文件只發送了細微的變化,它的 MD5 值也會發生很大的變化。
ETag 的用法以下:
//語法
ETag: "<etag_value>"
//實例
response.setHeader('ETag', fileMd5)
複製代碼
結果以下圖所示:
能夠看到,雖然是利用了緩存,但與前面的兩種方法相比,處理時間並不是爲 0ms。這是由於它確實向服務器發出了請求,只是服務器在比較 ETag 值以後,沒有將文件發送給瀏覽器而已。
Last-Modified 是一個響應首部,其中包含源頭服務器認定的資源作出修改的日期及時間。
與 ETag 相似,也是設定一個特徵值,服務器經過比較特徵值來判斷是否讓瀏覽器運用緩存,只不過 ETag 用的是文件的版本號,Last-Modified 用的是文件最後的修改時間。用法以下:
//語法
Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
//實例
let lastModified = fs.statSync('./css/style.css', 'utf8').mtime.toGMTString();
response.setHeader('Last-Modified', lastModified);
複製代碼
只要文件沒有改變,也就是文件修改時間沒有發生變化,那麼服務器便不會向瀏覽器發送這個文件,而是讓瀏覽器去讀取緩存。
與 ETag 相似的是,它也會發出請求,只是服務器不返回文件而已。