聊一聊 cookie

我們看到的 cookie

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。

我自己創建了一個網站,網址為http://ppsc.sankuai.com。在這個網頁中我設置了幾個cookieJSSESSIONIDPA_VTIMEskmtutctest

在 chrome 瀏覽器中打開這個網站,進入開發者模式,點擊Resources欄 -> 選擇cookies,我們會看到如下圖所示的界面:

?

解釋一下:左邊欄Cookies下方會列舉當前網頁中設置過cookie的域都有哪些。上圖中只有一個域,即“ppsc.sankuai.com”。而右側區域顯示的就是某個域下具體的?cookie?列表,對應上圖就是“ppsc.sankuai.com”域下設置的4個cookie

在這個網頁中我往http://ppsc.sankuai.com/getList接口發了一個 Ajax 請求,request header如下圖所示:

?

從上圖中我們會看到request header中自動添加了Cookie字段(我并沒有手動添加這個字段哦~),Cookie字段的值其實就是我設置的那4個?cookie。這個請求最終會發送到http://ppsc.sankuai.com這個服務器上,這個服務器就能從接收到的request header中提取那4個cookie

上面兩張圖展示了cookie的基本通信流程:設置cookie?=>?cookie被自動添加到request header中 => 服務端接收到cookie。這個流程中有幾個問題需要好好研究:

  1. 什么樣的數據適合放在cookie中?

  2. cookie是怎么設置的?

  3. cookie為什么會自動加到request header中?

  4. cookie怎么增刪查改?

我們要帶著這幾個問題繼續往下閱讀。

cookie 是怎么工作的?

首先必須明確一點,存儲cookie是瀏覽器提供的功能。cookie?其實是存儲在瀏覽器中的純文本,瀏覽器的安裝目錄下會專門有一個 cookie 文件夾來存放各個域下設置的cookie

當網頁要發http請求時,瀏覽器會先檢查是否有相應的cookie,有則自動添加在request header中的cookie字段中。這些是瀏覽器自動幫我們做的,而且每一次http請求瀏覽器都會自動幫我們做。這個特點很重要,因為這關系到“什么樣的數據適合存儲在cookie中”。

存儲在cookie中的數據,每次都會被瀏覽器自動放在http請求中,如果這些數據并不是每個請求都需要發給服務端的數據,瀏覽器這設置自動處理無疑增加了網絡開銷;但如果這些數據是每個請求都需要發給服務端的數據(比如身份認證信息),瀏覽器這設置自動處理就大大免去了重復添加操作。所以對于那設置“每次請求都要攜帶的信息(最典型的就是身份認證信息)”就特別適合放在cookie中,其他類型的數據就不適合了。

但在 localStorage 出現之前,cookie被濫用當做了存儲工具。什么數據都放在cookie中,即使這些數據只在頁面中使用而不需要隨請求傳送到服務端。當然cookie標準還是做了一些限制的:每個域名下的cookie 的大小最大為4KB,每個域名下的cookie數量最多為20個(但很多瀏覽器廠商在具體實現時支持大于20個)。

cookie 的格式

document.cookie

JS 原生的 API提供了獲取cookie的方法:document.cookie(注意,這個方法只能獲取非 HttpOnly 類型的cookie)。在 console 中執行這段代碼可以看到結果如下圖:

?

打印出的結果是一個字符串類型,因為cookie本身就是存儲在瀏覽器中的字符串。但這個字符串是有格式的,由鍵值對?key=value構成,鍵值對之間由一個分號和一個空格隔開。

cookie 的屬性選項

每個cookie都有一定的屬性,如什么時候失效,要發送到哪個域名,哪個路徑等等。這些屬性是通過cookie選項來設置的,cookie選項包括:expiresdomainpathsecureHttpOnly。在設置任一個cookie時都可以設置相關的這些屬性,當然也可以不設置,這時會使用這些屬性的默認值。在設置這些屬性時,屬性之間由一個分號和一個空格隔開。代碼示例如下:

"key=name; expires=Thu, 25 Feb 2016 04:18:00 GMT; domain=ppsc.sankuai.com; path=/; secure; HttpOnly"

expires

expires選項用來設置“cookie 什么時間內有效”。expires其實是cookie失效日期,expires必須是?GMT?格式的時間(可以通過?new Date().toGMTString()或者?new Date().toUTCString()?來獲得)。

expires=Thu, 25 Feb 2016 04:18:00 GMT表示cookie講在2016年2月25日4:18分之后失效,對于失效的cookie瀏覽器會清空。如果沒有設置該選項,則默認有效期為session,即會話cookie。這種cookie在瀏覽器關閉后就沒有了。

expires?是 http/1.0協議中的選項,在新的http/1.1協議中expires已經由?max-age?選項代替,兩者的作用都是限制cookie 的有效時間。expires的值是一個時間點(cookie失效時刻= expires),而max-age?的值是一個以為單位時間段(cookie失效時刻= 創建時刻+ max-age)。
另外,max-age?的默認值是?-1(即有效期為?session?);若max-age有三種可能值:負數、0、正數。負數:有效期session0:刪除cookie;正數:有效期為創建時刻+ max-age

domain 和 path

domain是域名,path是路徑,兩者加起來就構成了 URL,domainpath一起來限制 cookie 能被哪些 URL 訪問。

一句話概括:某cookie的?domain為“baidu.com”,?path為“/ ”,若請求的URL(URL 可以是js/html/img/css資源請求,但不包括 XHR 請求)的域名是“baidu.com”或其子域如“api.baidu.com”、“dev.api.baidu.com”,且 URL 的路徑是“/ ”或子路徑“/home”、“/home/login”,則瀏覽器會將此 cookie 添加到該請求的 cookie 頭部中。

所以domainpath2個選項共同決定了cookie何時被瀏覽器自動添加到請求頭部中發送出去。如果沒有設置這兩個選項,則會使用默認值。domain的默認值為設置該cookie的網頁所在的域名,path默認值為設置該cookie的網頁所在的目錄。

特別說明1:
發生跨域xhr請求時,即使請求URL的域名和路徑都滿足 cookie 的 domain 和 path,默認情況下cookie也不會自動被添加到請求頭部中。若想知道原因請閱讀本文最后一節)

特別說明2:
domain是可以設置為頁面本身的域名(本域),或頁面本身域名的父域,但不能是公共后綴?public suffix。舉例說明下:如果頁面域名為 www.baidu.com, domain可以設置為“www.baidu.com”,也可以設置為“baidu.com”,但不能設置為“.com”或“com”。

secure

secure選項用來設置cookie只在確保安全的請求中才會發送。當請求是HTTPS或者其他安全協議時,包含?secure?選項的?cookie?才能被發送至服務器。

默認情況下,cookie不會帶secure選項(即為空)。所以默認情況下,不管是HTTPS協議還是HTTP協議的請求,cookie?都會被發送至服務端。但要注意一點,secure選項只是限定了在安全情況下才可以傳輸給服務端,但并不代表你不能看到這個 cookie。

下面我們設置一個?secure類型的 cookie:

document.cookie =?"name=huang; secure";

之后你就能在控制臺中看到這個 cookie 了,如下圖所示:

?

這里有個坑需要注意下:
如果想在客戶端即網頁中通過 js 去設置secure類型的 cookie,必須保證網頁是https協議的。在http協議的網頁中是無法設置secure類型cookie的。

httpOnly

這個選項用來設置cookie是否能通過?js?去訪問。默認情況下,cookie不會帶httpOnly選項(即為空),所以默認情況下,客戶端是可以通過js代碼去訪問(包括讀取、修改、刪除等)這個cookie的。當cookiehttpOnly選項時,客戶端則無法通過js代碼去訪問(包括讀取、修改、刪除等)這個cookie

在客戶端是不能通過js代碼去設置一個httpOnly類型的cookie的,這種類型的cookie只能通過服務端來設置。

那我們在頁面中怎么知道哪些cookiehttpOnly類型的呢?看下圖:

?

凡是httpOnly類型的cookie,其 HTTP 一列都會打上√,如上圖中的PA_VTIME。你通過document.cookie是不能獲取的,也不能修改PA_VTIME的。

——httpOnly與安全

從上面介紹中,大家是否會有這樣的疑問:為什么我們要限制客戶端去訪問cookie?其實這樣做是為了保障安全。

試想:如果任何 cookie 都能被客戶端通過document.cookie獲取會發生什么可怕的事情。當我們的網頁遭受了 XSS 攻擊,有一段惡意的script腳本插到了網頁中。這段script腳本做的事情是:通過document.cookie讀取了用戶身份驗證相關的 cookie,并將這些 cookie 發送到了攻擊者的服務器。攻擊者輕而易舉就拿到了用戶身份驗證信息,于是就可以搖搖大擺地冒充此用戶訪問你的服務器了(因為攻擊者有合法的用戶身份驗證信息,所以會通過你服務器的驗證)。

如何設置 cookie?

知道了cookie的格式,cookie的屬性選項,接下來我們就可以設置cookie了。首先得明確一點:cookie既可以由服務端來設置,也可以由客戶端來設置。

服務端設置 cookie

不管你是請求一個資源文件(如 html/js/css/圖片),還是發送一個ajax請求,服務端都會返回response。而response header中有一項叫set-cookie,是服務端專門用來設置cookie的。如下圖所示,服務端返回的response header中有5個set-cookie字段,每個字段對應一個cookie(注意不能將多個cookie放在一個set-cookie字段中),set-cookie字段的值就是普通的字符串,每個cookie還設置了相關屬性選項。

注意:

  • 一個set-Cookie字段只能設置一個cookie,當你要想設置多個 cookie,需要添加同樣多的set-Cookie字段。

  • 服務端可以設置cookie 的所有選項:expiresdomainpathsecureHttpOnly

客戶端設置 cookie

在網頁即客戶端中我們也可以通過js代碼來設置cookie。如我當前打開的網址為http://dxw.st.sankuai.com/mp/,在控制臺中我們執行了下面代碼:

document.cookie =?"name=Jonh; ";

查看瀏覽器 cookie 面板如下圖所示,cookie確實設置成功了,而且屬性選項?domainpathexpires都用了默認值。

?

再執行下面代碼:

document.cookie="age=12; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";

查看瀏覽器cookie 面板,如下圖所示,新的cookie設置成功了,而且屬性選項?domainpathexpires都變成了設定的值。

?

注意:

  • 客戶端可以設置cookie 的下列選項:expiresdomainpathsecure(有條件:只有在https協議的網頁中,客戶端設置secure類型的 cookie 才能成功),但無法設置HttpOnly選項。

用 js 如何設置多個 cookie

當要設置多個cookie時, js 代碼很自然地我們會這么寫:

document.cookie =?"name=Jonh; age=12; class=111";

但你會發現這樣寫只是添加了第一個cookie“name=John”,后面的所有cookie都沒有添加成功。所以最簡單的設置多個cookie的方法就在重復執行document.cookie = "key=name",如下:

document.cookie = "name=Jonh";
document.cookie = "age=12";
document.cookie = "class=111";

如何修改、刪除

修改 cookie

要想修改一個cookie,只需要重新賦值就行,舊的值會被新的值覆蓋。但要注意一點,在設置新cookie時,path/domain這幾個選項一定要舊cookie 保持一樣。否則不會修改舊值,而是添加了一個新的 cookie。

刪除 cookie

刪除一個cookie?也挺簡單,也是重新賦值,只要將這個新cookie的expires?選項設置為一個過去的時間點就行了。但同樣要注意,path/domain/這幾個選項一定要舊cookie 保持一樣。

cookie 編碼

cookie其實是個字符串,但這個字符串中逗號、分號、空格被當做了特殊符號。所以當cookie的 key 和 value 中含有這3個特殊字符時,需要對其進行額外編碼,一般會用escape進行編碼,讀取時用unescape進行解碼;當然也可以用encodeURIComponent/decodeURIComponent或者encodeURI/decodeURI(三者的區別可以參考這篇文章)。

var key = escape("name;value");
var value = escape("this is a value contain , and ;");
document.cookie= key + "=" + value + "; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/";

跨域請求中 cookie

之前在介紹 XHR 的一篇文章里面提過:默認情況下,在發生跨域時,cookie 作為一種 credential 信息是不會被傳送到服務端的。必須要進行額外設置才可以。具體原因和如何設置可以參考我的這篇文章:你真的會使用XMLHttpRequest嗎?

另外,關于跨域資源共享?CORS極力推薦大家閱讀阮一峰老師的這篇?跨域資源共享 CORS 詳解。

其他補充

  1. 什么時候 cookie 會被覆蓋:name/domain/path 這3個字段都相同的時候;

  2. 關于domain的補充說明(參考1/參考2):

    1. 如果顯式設置了 domain,則設置成什么,瀏覽器就存成什么;但如果沒有顯式設置,則瀏覽器會自動取 url 的 host 作為 domain 值;

    2. 新的規范中,顯式設置 domain 時,如果 value 最前面帶點,則瀏覽器處理時會將這個點去掉,所以最后瀏覽器存的就是沒有點的(注意:但目前大多數瀏覽器并未全部這么實現)

    3. 前面帶點‘.’和不帶點‘.’有啥區別:

      • 帶點:任何 subdomain 都可以訪問,包括父 domain

      • 不帶點:只有完全一樣的域名才能訪問,subdomain 不能(但在 IE 下比較特殊,它支持 subdomain 訪問)

?

?

?

轉自:https://segmentfault.com/a/1190000004556040#articleHeader6

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/448366.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/448366.shtml
英文地址,請注明出處:http://en.pswp.cn/news/448366.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

跨域資源共享 CORS 詳解

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。 它允許瀏覽…

油門

定義 油門是內燃機上控制燃料供量的裝置。作用 是汽車發動機與摩托車油箱之間的閥門,控制汽油的量。操作注意 1.空車起步勿用大油門,以小油門為宜,負荷起步則以中油門為宜。 2.啟動時將油門放在合適位,使機件不易磨損。…

C++之泛型編程(模板)

1.模板綜述 背景 有時候許多函數或子程序的邏輯結構是一樣的,只是要處理的數據類型不一樣有時候多個類具有相同邏輯的成員函數和成員變量,只是成員變量的數據類型以及成員函數的參數類型不一樣模板就是解決數據類型不一致造成代碼冗余的一種機制&#xf…

Base64轉PDF、PDF轉IMG(使用pdfbox插件)

--添加依賴 <!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --><dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.12</version></dependency&…

const的用法,特別是用在函數后面

原文出處&#xff1a;http://blog.csdn.net/zcf1002797280/article/details/7816977

圖解 Linux 安裝 JDK1.8 、配置環境變量

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 到官網下載 JDK 1.8 https://www.oracle.com/technetwork/java/javase/downloads/index.html 2. 用 rz 命令把 jdk-8u191-linux-x6…

剎車

定義 剎車就是可以減慢車速的機械制動裝置&#xff0c;又名減速器。簡單來說&#xff0c;汽車剎車踏板在方向盤下面&#xff0c;踩住剎車踏板&#xff0c;則使剎車杠桿聯動受壓并傳至到剎車鼓上的剎車片卡住剎車輪盤&#xff0c;使汽車減速或停止運行。作用 目的是減速&a…

【原創】Performanced C++ 經驗規則 第五條:再談重載、覆蓋和隱藏

第五條&#xff1a;再談重載、覆蓋和隱藏 在C中&#xff0c;無論在類作用域內還是外&#xff0c;兩個&#xff08;或多個&#xff09;同名的函數&#xff0c;可能且僅可能是以下三種關系&#xff1a;重載&#xff08;Overload&#xff09;、覆蓋&#xff08;Override&#xff0…

C++之純虛函數和抽象類

純虛函數和抽象類 1.基本概念 2.案例 #include <iostream> using namespace std;////面向抽象類編程(面向一套預先定義好的接口編程)//解耦合 ....模塊的劃分class Figure //抽象類 { public://閱讀一個統一的界面(接口),讓子類使用,讓子類必須去實現virtual void get…

解決: -bash: $‘\302\240docker‘: command not found

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 我只是運行 一條很簡單的啟動容器的命令&#xff0c;多次執行都報錯&#xff0c;報錯如題&#xff1a; -bash: $\302\240docker: comma…

換擋/掛檔

定義 換擋/掛檔是指變速器&#xff0c;用于轉變發動機曲軸的轉矩及轉速&#xff0c;以適應汽車在起步、加速、行駛以及克服各種道路阻礙等不同行駛條件下對驅動車輪牽引力及車速不同要求的需要。作用 使汽車能以非常低的穩定車速行駛&#xff0c;而這種低的轉速只靠內然…

sql:無法解決 equal to 操作中 Chinese_PRC_CI_AS 和 Chinese_Taiwan_Stroke_CI_AS 之間的排序規則沖突。...

--無法解決 equal to 操作中 "Chinese_PRC_CI_AS" 和 "Chinese_Taiwan_Stroke_CI_AS" 之間的排序規則沖突。 CREATE VIEW View_VipBranchStaffBranchList AS select VipBranchStaff.*,geovindu_branch.B_Name,VipExamCountry.ExamCountryName from VipBran…

【汽車取證篇】GA-T 1998-2022《汽車車載電子數據提取技術規范》(附下載)

【汽車取證篇】GA-T 1998-2022《汽車車載電子數據提取技術規范》&#xff08;附下載&#xff09; GA-T 1998-2022《汽車車載電子數據提取技術規范》標準—【蘇小沐】 總結 公眾號回復關鍵詞【汽車取證】自動獲取資源合集&#xff0c;如鏈接失效請留言&#xff0c;便于…

解決: Client does not support authentication protocol requested by server; consider upgrading MySQL

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 在服務器上把 mysql 裝好后&#xff0c;運行起來。 2. navicat 死活連接不上&#xff0c;在網上查說是要改數據庫賬號、密碼什么的&…

C++之STL理論基礎

1.基本概念 STL&#xff08;Standard Template Library&#xff0c;標準模板庫)是惠普實驗室開發的一系列軟件的統稱。雖然主要出現在C中&#xff0c;但在被引入C之前該技術就已經存在了很長的一段時間。 STL的從廣義上講分為三部分&#xff1a;algorithm&#xff08;算法&am…

方向盤

定義 方向盤是汽車、輪船、飛機等的操縱行駛方向的輪狀裝置。 構成 一般由骨架和發泡組合起來就是最簡單的方向盤了&#xff0c;而方向盤上都會有和主駕駛氣囊對應的安裝卡扣或螺釘孔&#xff0c;其下方一般會有多功能開關模塊。作用 方向盤不僅可以控制車輛的方向…

數據庫范式俗話

1NF&#xff1a;一個table中的列是不可再分的&#xff08;即列的原子性&#xff09; 2NF&#xff1a;一個table中的行是可以唯一標示的&#xff0c;&#xff08;即table中的行是不可以 重復的&#xff09; 3NF&#xff1a;一個table中的列不依賴于另一個table中的非主鍵列 4NF&…

STL之string類型

1.String概念 string是STL的字符串類型&#xff0c;通常用來表示字符串。而在使用string之前&#xff0c;字符串通常是用char*表示的。 string和char*的區別&#xff1a; string是一個類, char*是一個指向字符的指針。 string封裝了char*&#xff0c;管理這個字符串&#x…

解決maven打包報錯:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 一、報錯經歷&#xff1a; 今天使用eclipse通過maven install打war包的時候&#xff0c;出現了下圖所示的錯誤 二、問題分析&#xff1a…

離合器

離合器的定義 汽車離合器位于發動機和變速箱之間的飛輪殼內&#xff0c;用螺釘將離合器總成固定在飛輪的后平面上&#xff0c;離合器的輸出軸就是變速箱的輸入軸。在汽車行駛過程中&#xff0c;駕駛員可根據需要踩下或松開離合器踏板&#xff0c;使發動機與變速箱暫時分離和…