Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
天的論題是cookie的作用及cookie 的分類。首先cookie是追蹤訪問者行為中的重要一環,在所有的檢測系統和追蹤工具中想是不可或缺的。cookie最初的作用并不是用來追蹤訪問者行為,而是網站用來記錄訪問者的用戶信息、歷史記錄、訪問偏好,以及判定老訪客的登錄狀態,并且通過這世信息提升訪問者在網站的使用體驗。
例如:新訪客并不需要每次都以用戶名和密碼進行登錄操作,在訪問淘寶時,可以看到上次瀏情的商品信息。這些都是依靠Cookie中存儲的信息如果將瀏覽器中所有Cookie都清空,再訪問經常光顧的網站時就會發現Cookie有多重要了。
cookies分為第一方Cookie和第三方Cookie,這兩類Cookie都是網站保存在用戶電腦上的一個文件,它們都由某個特定的域創建,并且只能被這個域訪問。我們可以通過瀏覽器或第三方工具來查看網站對我們設置的Cookie情況,它們之間的區別歸根結底在于是什么域名創建了 cookies。
第一方 cookie 指的是由網絡用戶訪問的域創建的 cookie。例如:當用戶通過網絡瀏覽器點擊我博客rrdaj.com 時,瀏覽器會在第一個頁面中發送一個網頁請求,這個過程需要用戶直接與 rrdaj.com 互動。這樣網絡瀏覽器隨后就將此數據文件保存到“rrdaj.com”域名下的用戶計算機上。
大多數網頁瀏覽器都支持第一方 cookies。
為什么?
因為如果你禁用第一方 cookies,當你瀏覽網頁從一頁跳到另一頁的時候,網站無法跟蹤你的活動。再比如:每次你從購物網站的其他頁面向購物車添加一些東西,它就會被視為一個新的動作而沒有被記錄下來,這樣你將無法在同一交易中在線購買多個商品了。
第三方cookie是建立在別的域名不是你訪問的域名(地址欄中的網址), 比如:廣告網絡商就是最常見的第三方 cookies 的來源,他們用它們在多個網站上追蹤用戶的行為,當然這些活動可以用來調整廣告。此外圖像、 JavaScript 和 iframe 通常也會導致第三方 cookies 的生成。
像前不久的GDPR,用戶就不會像第一方cookie那樣對第三方 cookies 那么友好了,有的用戶就不會對它進行買單。
為什么?
因為許多人認為這是對他們隱私的侵犯,是對他們數字安全的威脅。(例如:下圖baidu.com就是屬于第三方的cookie記錄)
對于第三方 cookies 來說,最常見的用法是在不同領域去跟蹤用戶,尤其是廣告商。在識別和跟蹤單個域名的用戶時,第一方 cookie 非常有用。
然而,有時候你想要在多個領域跟蹤用戶,比如:
(1)你經營著一個擁有多個子品牌的大品牌,如果你是一家比較大的零售商或食品飲料公司或者是電商,你可能會在主品牌下擁有多個品牌,例如:大家都熟悉的服飾品牌Gap旗下就有好幾個子品牌(GAP、Banana Republic、Old Navy、Piperlime、Athleta),每個子品牌都有自己的域名。
因此也有自己的第一方cookie,這意味著主品牌www.gap.com母公司不能使用第一方 cookies 來識別其他子品牌網站上的用戶了。這樣第三方cookie就起作用了,可以用它去追蹤子品牌,比如:ab-inbev.com下的用戶行為,方便做大數據管理。
(2)第二種情況就是我上面說的廣告商,這個好理解,比如:我們熟知的Google Adsense ,通過第三方cookie,谷歌可以通過他們去識別這些1400多萬個網站(可能還有更多)的用戶信息,國內有很多廣告聯盟也是同樣的道理。
因此,應對方法就出來了,一些用戶使用像 AdBlock Plus 和 NoScript 這樣的插件來阻止諸如廣告和 JavaScript 之類的東西在網站上加載,從而阻止了第三方 cookies 的創建。更常見的是,或者他們使用配置他們的瀏覽設置,這樣網頁瀏覽器就會屏蔽或清除它們。
作者:該吃藥了,公號:ISEOers(ID:iseo888)
本文由 @該吃藥了原創發布于人人都是產品經理。未經許可,禁止轉載
題圖來自Unsplash,基于CC0協議
先要了解HTTP是無狀態的Web服務器,什么是無狀態呢?一次對話完成后下一次對話完全不知道上一次對話發生了什么。如果在Web服務器中只是用來管理靜態文件還好說,對方是誰并不重要,把文件從磁盤中讀取出來發出去即可。但是隨著網絡的不斷發展,比如電商中的購物車只有記住了用戶的身份才能夠執行接下來的一系列動作。所以此時就需要我們無狀態的服務器記住一些事情。
那么Web服務器是如何記住一些事情呢?既然Web服務器記不住東西,那么我們就在外部想辦法記住,相當于服務器給每個客戶端都貼上了一個小紙條。上面記錄了服務器給我們返回的一些信息。然后服務器看到這張小紙條就知道我們是誰了。那么Cookie是誰產生的呢?Cookies是由服務器產生的。接下來我們描述一下Cookie產生的過程
瀏覽器第一次訪問服務端時,服務器此時肯定不知道他的身份,所以創建一個獨特的身份標識數據,格式為key=value,放入到Set-Cookie字段里,隨著響應報文發給瀏覽器。
瀏覽器看到有Set-Cookie字段以后就知道這是服務器給的身份標識,于是就保存起來,下次請求時會自動將此key=value值放入到Cookie字段中發給服務端。
服務端收到請求報文后,發現Cookie字段中有值,就能根據此值識別用戶的身份然后提供個性化的服務。
如何創建 Cookie
Servlet 程序中的代碼:
protected void createCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1 創建Cookie對象
Cookie cookie=new Cookie("key4", "value4");
//2 通知客戶端保存Cookie
resp.addCookie(cookie);
//1 創建Cookie對象
Cookie cookie1=new Cookie("key5", "value5");
//2 通知客戶端保存Cookie
resp.addCookie(cookie1);
resp.getWriter().write("Cookie創建成功");
}
Cookie創建成功!
服務器獲取客戶端的 Cookie 只需要一行代碼:req.getCookies():Cookie[]
Cookie 的工具類:
public class CookieUtils {
/**
* 查找指定名稱的 Cookie 對象
* @param name
* @param cookies
* @return
*/
public static Cookie findCookie(String name , Cookie[] cookies){
if (name==null || cookies==null || cookies.length==0) {
return null;
}
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
}
Servlet 程序中的代碼:
protected void getCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies=req.getCookies();
for (Cookie cookie : cookies) {
// getName方法返回Cookie的key(名)
// getValue方法返回Cookie的value值
resp.getWriter().write("Cookie[" + cookie.getName() + "=" + cookie.getValue() + "] <br/>");
}
Cookie iWantCookie=CookieUtils.findCookie("key1", cookies);
// 如果不等于null,說明賦過值,也就是找到了需要的Cookie
if (iWantCookie !=null) {
resp.getWriter().write("找到了需要的Cookie");
}
}
方法一:
1、先創建一個要修改的同名(指的就是 key)的 Cookie 對象
2、在構造器,同時賦于新的 Cookie 值。
3、調用 response.addCookie( Cookie );
// 1 、先創建一個要修改的同名的 Cookie 對象
// 2 、在構造器,同時賦于新的 Cookie 值。
Cookie cookie=new Cookie("key1","newValue1");
// 3 、調用 response.addCookie( Cookie ); 通知 客戶端 保存修改
resp.addCookie(cookie);
方法二:
1、先查找到需要修改的 Cookie 對象
2、調用 setValue()方法賦于新的 Cookie 值。
3、調用 response.addCookie()通知客戶端保存修改
1 、先查找到需要修改的 Cookie 對象
Cookie cookie=CookieUtils.findCookie("key2", req.getCookies());
if (cookie !=null) {
// 2 、調用 setValue() 方法賦于新的 Cookie 值。
cookie.setValue("newValue2");
// 3 、調用 response.addCookie() 通知客戶端保存修改
resp.addCookie(cookie);
}
在頁面空白區域右鍵,然后點擊檢查:
Cookie 的生命控制指的是如何管理 Cookie 什么時候被銷毀(刪除)
setMaxAge()
正數,表示在指定的秒數后過期
負數,表示瀏覽器一關,Cookie 就會被刪除(默認值是-1)
零,表示馬上刪除 Cookie
例:
protected void life3600(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
Cookie cookie=new Cookie("life3600", "life3600");
cookie.setMaxAge(60 * 60); // 設置 Cookie 一小時之后被刪除。無效
resp.addCookie(cookie);
resp.getWriter().write(" 已經創建了一個存活一小時的 Cookie");
}
protected void deleteNow(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
// 先找到你要刪除的 Cookie 對象
Cookie cookie=CookieUtils.findCookie("key4", req.getCookies());
if (cookie !=null) {
// 調用 setMaxAge(0);
cookie.setMaxAge(0); // 表示馬上刪除,都不需要等待瀏覽器關閉
// 調用 response.addCookie(cookie);
resp.addCookie(cookie);
resp.getWriter().write("key4 的 的 Cookie 已經被刪除");
}
}
protected void defaultLife(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
Cookie cookie=new Cookie("defalutLife","defaultLife");
cookie.setMaxAge(-1);// 設置存活時間
resp.addCookie(cookie);
}
Cookie 的 path 屬性可以有效的過濾哪些 Cookie 可以發送給服務器。哪些不發。
path 屬性是通過請求的地址來進行有效的過濾。
CookieA path=/工程路徑
CookieB path=/工程路徑/abc
請求地址如下:
http://ip:port/工程路徑/a.html
CookieA 發送
CookieB 不發送
http://ip:port/工程路徑/abc/a.html
CookieA 發送
CookieB 發送
例:
protected void testPath(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
Cookie cookie=new Cookie("path1", "path1");
// getContextPath()===>>>> 得到工程路徑
cookie.setPath( req.getContextPath() + "/abc" ); //===>>>> / 工程路徑 /abc
resp.addCookie(cookie);
resp.getWriter().write(" 創建了一個帶有 Path 路徑的 Cookie");
}
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登錄頁面</title>
</head>
<body>
<form action="http://localhost:8080/Test/loginServlet" method="get">
用戶名:<input type="text" name="username" value="${cookie.username.value}"> <br>
密碼:<input type="password" name="password"> <br>
<input type="submit" value="登錄">
</form>
</body>
</html>
LoginServlet :
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username=req.getParameter("username");
String password=req.getParameter("password");
if ("kailong".equals(username) && "123456".equals(password)) {
//登錄 成功
Cookie cookie=new Cookie("username", username);
cookie.setMaxAge(60 * 60 * 24 * 7);//當前Cookie一周內有效
resp.addCookie(cookie);
System.out.println("登錄 成功");
} else {
// 登錄 失敗
System.out.println("登錄 失敗");
}
}
}
試驗:
第一次登錄:
點擊登錄后,控制臺顯示登錄成功
然后我們關了瀏覽器再打開這個頁面
再打開這個頁面可以發現用戶名已經存在,這就是cookie保存了用戶名信息,然后這里設置的是Cookie有效期為一周,一周后該Cookie就失效了
公眾號本文地址:一文了解Cookie
歡迎關注公眾號:愚生淺末。
正式介紹cookie之前我們要先來說一說網絡通訊協議
首先:什么是網絡通訊協議?所謂協議一般就是甲乙雙方溝通要遵循的規則與方式,那么通訊協議就是通訊雙方要遵循的規則,網絡通訊協議則是計算機雙方傳輸數據所要遵循的協議,瀏覽網頁時, 一般使用http或者https,而它們都是基于TCP/IP協議的。
在發送數據之前,都必須先在雙方之間建立一條連接。在TCP/IP協議中,TCP 協議提供可靠的連接服務,連接是通過三次握手進行初始化的,如下圖:
客戶端要向服務器發送請求,首先會發送一個請求連接,這是第一次握手;
當服務器收到這個請求以后返回給客戶端一條消息,這是第二次握手;
然后客戶端再把確認消息發給服務器,這是第三次握手;
經過這三次握手客戶端與服務器之間的連接就建立起來了。
就像打電話一樣,客戶端向服務器撥通電話,服務器接起電話,說了一句:“喂?”,然后客戶端收到了這句“喂”,再跟服務器說一聲“喂!”,連接就建立好了,可以愉快的通話了
建立連接需要經過三次握手,那數據傳輸結束以后呢?我們打電話事情說完了要掛掉電話要經歷一個怎樣的過程?可能對話是下面這樣的:
A:“我掛了”
B:“好”
A:“拜拜”
B:“拜拜,我也掛了”
A:“好,拜拜”
B:“嗯嗯,拜拜,掛了”
A:“好,拜拜”
B:“拜拜”
有點搞笑 ,經過好多次消息確認好不容易才能把電話掛掉,但這并不是無聊,而是要互相確認對方是否真的已經準備斷開連接了,那么我們的TCP/IP協議也會考慮到這一點,要斷開連接會經過四次揮手,如下圖:
數據傳輸結束時,客戶端向服務器發送一條結束的消息,服務器收到消息后會馬上返回給客戶端確認消息,并隨后發送一條“我也結束了”的消息,當客戶端收到這條消息以后會響應給服務器確認消息,服務器收到這條確認消息以后就會關閉,而客戶端則會等待兩個單位時間之后關閉。注意這里客戶端并不是立馬關閉,而是會等帶兩個單位時間,為什么是兩個單位時間呢?首先,所謂的單位時間指的是一次前后端數據傳輸所花費的時間,這里要等待兩個單位時間是因為客戶端要等數據發送到服務器以后確認收不到數據返回,這一來一去就是兩個單位時間了,因為如果這個時候服務器并沒有結束的話會再次給客戶端響應,而客戶端在兩個單位時間后收不到響應則代表本次數據傳輸正式結束。
下面貼出兩張動圖:
這兩張動圖對于計算機專業的讀者可以嘗試探究,本文不做詳細展開
HTTP協議, 使我們用戶上網常見的協議, 簡單的理解, 它是基于TCP/IP協議改造加工出來的,也就是說每一個http請求都會通過三次握手建立連接,傳輸數據, 然后四次揮手斷開連接.
例如當你登錄淘寶的時候, 你的瀏覽器跟淘寶服務器之間就行了 一個 http鏈接.
然后, 當首頁數據加載完成, 鏈接就斷開了.
這時服務就無法保存你的狀態. 你瀏覽了什么商品? 購物車加了幾個東西? 有沒有關閉瀏覽器? 服務器統統不知道了
所以, 我們說:http協議是一種無狀態協議,這里的無狀態指的是無法保存狀態,因為一旦數據傳輸結束連接就會斷開,就無法獲取一些狀態了,這樣設計的好處就是可以節約資源,需要的時候才發出請求,但是也會造成一些困擾,
尤其是關于身份驗證. 用戶在登錄頁面完成了登錄,那么接下來就會回到首頁或者其他頁面進行操作,但問題是這個時候登錄的這次http請求已經結束了,所以當完成頁面跳轉之后就取不到登錄狀態了,那怎么辦?再登錄一次?
當你反復使用http協議跟服務器建立鏈接的時候, 服務器怎么才能知道, 你是一個登錄過的合法用戶?? 為了解決這個問題, 出現了cookie技術.
cookie稱之為會話跟蹤技術,顧名思義,就是在一次會話中跟蹤記錄一些狀態。首先,所謂的”會話“指的就是從瀏覽器打開一個網站到訪問它的其他網頁直到瀏覽器關閉的這個過程。
cookie就可以在一次會話從開始到結束的整個過程,全程跟蹤記錄客戶端的狀態(例如:是否登錄、購物車信息、是否已下載、是否 已點贊、視頻播放進度等等)。
cookie是服務器存儲在客戶端本地的一個文件. 它就好比服務器發給客戶端的一個身份標識, 有了這個身份牌, 只要客戶端隨身攜帶這個身份牌. 服務器就能識別我們的身份了
其實, 如果是單純的身份驗證場景下, 前端開發是用不到cookie的
從服務器發送cookie給瀏覽器, 瀏覽器保存cookie, 到瀏覽器每次發送請求 ,攜帶著cookie文件, 這些事情瀏覽器全部都可以自己完成. 根本不需要我們前端開發人員參與.
但我們有時也會利用cookie, 在前端存儲一些狀態信息.
比如某個視頻看到了32分15秒.
我們可以通過前端操作, 直接將這個數據保存在本地cookie文件中
下次打開網站, 我們再次讀取這個信息
然后直接向服務器請求32分16秒的視頻內容.
cookie的使用方式很簡單 ,系統提供的只有一個屬性 document.cookie,無論是存還是取或者其他操作都是通過這一個屬性來完成(注:cookie是http協議下的技術,所以不要用file的方式打開本地html文件測試cookie,雖然由部分瀏覽器也在file協議下實現了cookie,但是不推薦這么做)。
首先,我們來看看如何存:
document.cookie='username=dary' // 存一條username為dary的cookie
但是如果當我們要存一條中文的cookie,比如:username=張三,在部分低版本瀏覽器就會遇到一些位置錯誤,這時就可以使用 encodeURIComponent 編碼對中文進行編碼:
document.cookie=`username=encodeURIComponent('大林')`
可以看到,中文內容已經被編碼了,以后取得時候我們可以通過decodeURIComponent 方法進行解碼,下文會提到
現在我們回頭去看看上面我們存過的cookie,其中有Expires/max-Age選項,這一項指的就是cookie的有效期,我們可以看到是session,代表會話期,也就是默認的會話結束cookie失效,這時我們重啟瀏覽器就看不到這條cookie了。
除了默認的會話過期我們還可以手動設置cookie的過期時間,比如:7天后過期
var date=new Date()
date.setDate(date.getDate() + 7)
document.cookie=`username=${encodeURIComponent('大林')};expires=${date.toUTCString()}`
我們可以看到過期時間已經是7天以后了,這里我用了toUTCString()方法轉成了標準時區,所以比北京時間快8個小時,這時我們關閉瀏覽器再次打開,仍然可以看到這條cookie
我們來測試一下路徑,隨便進入項目中某一個目錄或者新建一個目錄,然后把一下代碼放進去執行
document.cookie='username=dary'
我們可以看到,path不再是之前的 / 了,而是當前目錄,這時我們再回到首頁,你會發現,這條cookie不見了,因為外層時訪問不了內層目錄存的cookie的。
所以我們一般存cookie都會這么寫:
document.cookie='username=dary;path=/'
不管當前目錄是誰統一存根目錄,這樣項目中任意位置都可以訪問這一條cookie,這就perfect 啦!
由此:我們可以封裝一個存儲cookie的方法如下:
/** 存一條cookie
* @param {string} key 要存的cookie的名稱
* @param {string} value 要存的cookie的值
* @param {object} [options] 可選參數,過期時間和目錄,如:{ path: '/', expires: 7 }存根目錄7天過期的cookie
*/
function setCookie (key, value, options) {
var str=`${key}=${encodeURIComponent(value)}`
// 先判斷options是否傳進來了
if (options) {
// 如果傳進來了再判斷有哪個屬性
if (options.path) {
// 路徑拼接進去
str +=`;path=${options.path}`
}
if (options.expires) {
var date=new Date()
// 日期設置為過期時間
date.setDate(date.getDate() + options.expires)
str +=`;expires=${date.toUTCString()}`
}
}
document.cookie=str
}
現在我們掌握了如何存cookie,接下來看看怎么取吧
取cookie同樣使用document.cookie這個屬性:
console.log(document.cookie) // username=dary
但是如果我們在一個網站里存了多條cookie,這個時候得到的結果就是
console.log(document.cookie) // username=dary; age=18
多條cookie之間以; 隔開,注意:這里是分號和一個空格,這個對我們拆開每一條cookie非常重要。所以我們現在希望能把cookie每一條拆開,得到一個對象,這樣就可以取得某一條cookie的值了,所以我們可以封裝一個獲取cookie的方法如下:
/** 獲取某一條cookie
* @param {string} key 要獲取的cookie的名稱
* @retrun {string} 當前這條cookie的值
*/
getCookie (key) {
var str=document.cookie
var arr=str.split('; ')
var obj=new Object()
arr.forEach(item=> {
var subArr=item.split('=')
obj[subArr[0]]=decodeURIComponent(subArr[1])
})
return obj[key]
}
刪除cookie的方式特別簡單,我們只需要把cookie的過期時間設置為已經過去了的時間就行了,這個時候瀏覽器一看,誒?這條cookie不是已經過期了么?就只能把它刪掉了 ,方法如下:
/** 刪一條cookie
* @param {string} key 要刪的cookie的名稱
* @param {path} [path] 可選參數,要刪的cookie的所在的路徑,如果就是當前路徑這個參數可以不傳
*/
function removeCookie (key, path) {
var date=new Date()
date.setDate(date.getDate() - 1) // 過期時間設置為昨天
var str=`${key}='';expires=${date.toUTCString()}`
if (path) {
str +=`;path=${path}`
}
document.cookie=str
}
重新存一下把之前的覆蓋掉就是修改了cookie了
最后附上一個cookie方法,既可以完成存也可以取,甚至可以刪
*請認真填寫需求信息,我們會在24小時內與您取得聯系。