谈谈我熟悉又陌生的cookie
前言
大概是我的業務領域比較狹窄的原因,我總是會聽說cookie,卻很少在實際的開發中應用或者實踐過它,今天剛好看到<<JavaScript高級程序設計第三版>>的數據存儲部分,說到了cookie,這里就對cookie做一個深入訪談,希望和我一樣對cookie似曾相識的朋友可以真正的熟悉cookie,并學會利用cookie來服務我們的業務.^_^^_^
Cookie
定義
cookie,是服務器為了辨別用戶身份,進行session跟蹤而存儲在用戶本地終端上的數據(通常經過加密).
限制
域名限制
因為cookie一般用于與服務器進行交互,所以它一般存放在對應的域名下.當設定了一個cookie后,再給創建它的域名發送請求時,都會包含這個cookie,這個限制確保了儲存在cookie中的信息只能讓批準的接受者訪問,而無法被其他域訪問.
個數限制
由于cooki是存儲在客戶端計算機上的,還加入了一些限制確保cookie不會被惡意使用,同時不會占據太多磁盤空間.每個域的cookie總數是有限的,不過瀏覽器之間各有不同.
- IE7和之后的版本每個域名最多50個.
- Firefox限制每個域最多50個cookie
- Opera限制每個域最多30個cookie
- Safari 和Chrome 對每個域的cookie數量沒有硬性規定.
當超過單個域名限制之后還要在設置cookie,瀏覽器會清除以前設置的cookie.IE和Opera會刪除最近最少使用過的cookie.所以考慮cookie限制非常重要,避免出現不可預期的后果.
尺寸限制
瀏覽器中對于cookie的尺寸也有限制,大多數瀏覽器是4KB的長度限制,尺寸限制影響一個域下所有的cookie,而并非每個cookie單獨限制.
如果你嘗試創建查過最大限制的cookie,那么該cookie會被悄無聲息地丟掉.
cookie的構成
cookie由瀏覽器保存的以下幾塊信息構成.
- 名稱(name): 一個唯一確定cookie的名稱.
- 值(value): 存儲在cookie中的字符串值.
- 域(domain): cookie對于哪個域是有效的,控制只有向該域發送的請求才會包含這個cookie.
- 路徑(path): 對于指定域中的哪個路徑,應該向服務器發送cookie.
- 失效時間(expires): 表示cookie何時會被刪除的時間戳,沒有設置則默認是瀏覽器會話結束時,即將所有cookie刪除,若設置的失效日期是以前的時間,則cookie會被立刻刪除.
- 安全標志(secure): 制定后,cookie只有在使用SSL鏈接的時候才會發送到服務器,即https請求才可以發送cookie.
注意發送cookie的時候只會發送cookie的名和值才會被發送,其他值只會cookie信息的描述.
cookie的使用
使用場景
常用場景: cookie一般用來做登錄驗證,用戶登陸的時候講用戶名和密碼傳入到服務器端,服務器會返回將用戶相關的認證信息,然后由服務器將這些信息寫入cookie或者由前端使用js操作cookie將這些信息寫入到cookie中(如果服務器通過Set-Cookie的方式直接寫入則不需要前端的參與,前端是無感知的),登陸成功以后的用戶在該域名下的訪問都會在請求中發送cookie,作為該用戶的身份標識.我們這里主要討論的是前端使用js操作cookie的情況.
不常用場景: 我們也可以用js操作cookie,在cookie上存儲我們臨時需要的用于頁面交互的變量,這個時候cookie就充當了sessionStorage或者localStorage的角色.
操作cookie
由于JavaScript中讀寫cookie不是非常直觀,常常需要寫一些函數來簡化cookie的功能.基本的操作有三種: 讀取,寫入,刪除;
說明: 我不知道看這篇文章的朋友是不是了解這些操作cookie的方法,如果不了解,我建議你先想一想,然后嘗試著自己去寫,然后感興趣的話再來看看我的代碼,也可以分享到評論區,我們一起來看看這些實現方法的優劣,不知道不同思想的碰撞會不會擦出奇妙的火花呢? 很期待奧~
封裝的操作cookie的代碼如下:
const CookieUtil = {// 獲取cookie 接受的參數 cookie的名稱get: function(name) {var cookieName = encodeURIComponent(name) + "=",cookieStart = document.cookie.indexOf(cookieName),cookieValue = null;if(cookieStart !== -1) {var cookieEnd = document.cookie.indexOf(";",cookieStart);if(cookieEnd == -1) {cookieEnd = document.cookie.length;}cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.LENGTH, cookieEnd));}return cookieValue;},// 設置cookie, 接收參數: cookie的名稱, cookie的值, // 可選的用于執行cookie何時應被刪除的Date對象,cookie的可選的URL路徑, 可選的域和是否要添加secure標志的布爾值set: function (name, value, expires, path, domain, secure) {var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);if(expires instanceof Date) {cookieText += "; expires=" + expires.toGMTString();}if(path) {cookieText += "; path=" + path;}if(domain) {cookieText += "; domain=" + domain;}if(secure) {cookieText += "; secure";}document.cookie = cookieText;},// 刪除cookie的方法, 接收的參數: 要刪除的cookie的名稱,可選的路徑參數,可選的域參數和可選的安全參數unset: function (name, path, domain, secure) {// 將某個cookie的過期時間早于當前時間,則會被立刻刪除,該方法設置失效時間為1970年1月1日this.set(name, "", new Date(0), path, domain, secure);} }// 設置cookie CookieUtil.set("name", "Nicholas"); CookieUtil.set("book", "Professional JavaScript");// 讀取cookie的值 CookieUtil.get("name"); CookieUtil.get("book");// 刪除cookie CookieUtil.unset("name"); CookieUtil.unset("book");子cookie
為了繞開瀏覽器的單域名下的cookie數限制,一些開發人員使用了一種成為子cookie的改變,子cookie是存放在單個cookie中的更小段的數據,通常是多個名稱值對的形式.子cookie對常見的格式如下所示:
namename1=value1&name2=value2&name3=value3&name4=value4&name5=value5
子cookie一般也以查詢字符串的格式進行格式化,然后這些值可以使用單個cookie進行儲存和訪問,而非對每個名稱-值對兒使用不同的cookie存儲,最后網站或者web應用程序可以無需大到單域名cookie上限也可以存儲更加結構化的數據.
為了更好的操作子cookie,必須建立一系列新方法,子cookie的解析和序列化會因子cookie的期望用途而略有不同并更加復雜些,例如,要獲得一個子cookie,首先要遵循與獲得cookie一樣的基本步驟,但是在解碼cookie值之前,需要操作字符串,遍歷數組之類的操作來找出子cookie的信息.
說明: 我不知道看這篇文章的朋友是不是了解這些操作cookie的方法,如果不了解,我建議你先想一想,然后嘗試著自己去寫,然后感興趣的話再來看看我的代碼,也可以分享到評論區,我們一起來看看這些實現方法的優劣,不知道不同思想的碰撞會不會擦出奇妙的火花呢?
操作子cookie的方法如下:
// 操作子cookie的一組方法 var SubCookieUtil = {// 獲取cookie, 接收兩個參數,cookie名和子cookie名// 如果不穿子cookie名,則是普通的獲取方法,如果傳了,則取對應子cookie名的value.get: function (name, subName) {var subCookies = this.getAll(name);if(subCookies) {return subCookies[subName];} else {return null;}},// 判斷如果cookie中name對應的value不包含子cookie,// 則返回解碼后的cookieValue,如果包含子cookie,則返回處理后的result對象getAll: function (name) {var cookieName = encodeURIComponent(name) + "=",cookieStart = document.cookie.indexOf(cookieName),cookieEnd,result={},cookieValue= null,i,len,subCookies='',parts = [];if(cookieStart !== -1) {cookieEnd = document.cookie.indexOf(";", cookieStart);if(cookieEnd == -1) {cookieEnd = document.cookie.length;}cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd);if(cookieValue.length > 0) {if(cookieValue.indexOf("&") > -1) {subCookies = cookieValue.split("&");console.log("get subCookies",subCookies);for(i = 0,len = subCookies.length; i < len; i++) {parts = subCookies[i].split("=");result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);}} else {parts = cookieValue.split("=");result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1])}return result;}}return null;},// 同樣的,要設置子cookie,也有新的set方法set: function(name, subName, value, expires, path, domain, secure) {var subCookies = this.getAll(name) || {};subCookies[subName] = value;this.setAll(name, subCookies, expires, path, domain, secure);},setAll: function(name, subCookies, expires, path, domain, secure) {var cookieText = encodeURIComponent(name) + "=",subCookieParts = [],sub, result;// 將subCookies對象里的cookie值對編碼,并放進subCookieParts數組中for(sub in subCookies) {if(subCookies.hasOwnProperty(sub)) {subCookieParts.push(encodeURIComponent(sub)+ "=" + encodeURIComponent(subCookies[sub]));}}if(subCookieParts.length > 0) {cookieText += subCookieParts.join("&");if(expires instanceof Date) {cookieText += "; expires=" + expires.toGMTString();}} else {cookieText += "; expires=" + (new Date(0)).toGMTString();}if(path) {cookieText += "; path=" + path;}if(domain) {cookieText += "; domain=" + domain;}if(secure) {cookieText += "; secure";}document.cookie = cookieText; },// 刪除cookie 刪除單個cookieunset: function(name, subName, path, domain, secure) {var subCookies = this.getAll(name);subCookies[subName] ? delete subCookies[subName] : '';this.setAll(name, subCookies, null, path, domain, secure);},//刪除cookie 刪除多個cookie unsetAll: function (name, path, domain, secure) {this.setAll(name, null, new Date(0), path, domain, secure);} }// 假設 document.cookie = "data=name=Nicholas&book=Professional%20JavaScript" // 設置兩個cookie SubCookieUtil.set("xiaosisi", "name", "Nicholas"); SubCookieUtil.set("xiaosisi", "book", "Professional JavaScript"); SubCookieUtil.set("xiaosisi", "sisisi", "撕撕撕"); // 設置全部子cookie和失效日期 SubCookieUtil.setAll("xiaosisi", {name: "Nicholas", book:"Professional JavaScript", sisisi: "撕撕撕"}, new Date("2018-10-25")); // 修改名字的值,并修改失效日期 SubCookieUtil.setAll("xiaosisi", "name", "MIrascl", new Date("2018-11-25"));// 刪除名為sisisi的子cookie SubCookieUtil.unset("xiaosisi", "sisisi"); // 刪除整個cookie SubCookieUtil.unsetAll("xiaosisi");總結
關于cookie有兩點需要注意的地方:
第一: 由于所有的cookie都會由瀏覽器作為請求頭發送,所以在cookie中存儲大量信息會影響到特定域的請求性能,cookie信息越大,完成對服務器請求的時間也就越長.盡管瀏覽器對cookie的大做了限制,不過最好還是盡可能在cookie中少存儲信息,以免影響性能.
第二:一定不要在cookie中存儲重要和敏感的數據.cookie的存儲不是很安全,其中包含的任何數據都可以被他人訪問,重要的用戶信息不建議存儲在cookie里.
如果讀者們有關于cookie的比較好的使用策略歡迎在評論區留言或者私信我奧~共同進步是最讓人開心的事兒呢~~~
總結
以上是生活随笔為你收集整理的谈谈我熟悉又陌生的cookie的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 上扩展swap分区
- 下一篇: 弹性计算双周刊 第7期