FlashCookie比瀏覽器Cookie容量更大,可以跨瀏覽器對不同Cookies進行身份剔重,但是不易刪除。讓我們一起來看看如何關閉Flash Cookie吧:
1.用戶打開一個新的瀏覽器窗口,在瀏覽器中輸入如下網址:
http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager07.html
2.打開網頁可以看到每個網站所保存的flash cookie
3.選中相應的網站點擊“刪除Web站點”即可刪除這個網站的flash cookie,或者點擊“刪除所有Web站點”刪除所有網站的flash cookie。
介紹完了 Go 語言的 HTTP 請求和響應處理,接下來,我們來看看 Go 語言中 Cookie 技術的實現,由于 HTTP 協議本身是無狀態的,所以引入了 Cookie 來實現客戶端用戶識別和狀態管理,關于 Cookie 本身這里不多做介紹,你可以在維基百科或者閱讀 HTTP 報文首部字段(五):擴展字段篇(Cookie)這篇教程了解更多細節。
我們可以在 HTTP 響應頭中通過 Set-Cookie 字段設置 Cookie,然后在下次請求時就會在請求頭 Cookie 中自動包含新增的 Cookie。你可以在 Chrome 瀏覽器的控制臺中通過 Application->Storage->Cookies 查看指定域名下的所有 Cookie:
可以在 Cookie 列表頂部抬頭看到 Cookie 的所有屬性。
Go 專門提供了一個 http.Cookie 結構體來表示 Cookie,其中的字段對應著 Cookie 的所有屬性:
// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
// HTTP response or the Cookie header of an HTTP request.
//
// See https://tools.ietf.org/html/rfc6265 for details.
type Cookie struct {
Name string
Value string
Path string // optional
Domain string // optional
Expires time.Time // optional
RawExpires string // for reading cookies only
// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
MaxAge int
Secure bool
HttpOnly bool
SameSite SameSite
Raw string
Unparsed []string // Raw text of unparsed attribute-value pairs
}
我們可以將其與上面截圖中的 Cookie 屬性一一對應,如果你了解 Cookie 的基本結構的話,很容易知道每個字段的含義。如果你不了解的話,可以通過點擊上面 Cookie 簡介中給出的鏈接去了解。
這里,我們重點介紹下 Expires 字段:
有兩種方法來設置過期時間:一種是直接設置 Expires 字段,一種是設置 MaxAge 字段。前者表示到期的具體時間點,后者表示 Cookie 的有效時長(單位是秒)。這并不是 Go 語言的設計,而是不同瀏覽器的混亂標準使然,比如雖然 HTTP/1.1 有意廢棄 Expires,不過 IE 6、7、8 卻不支持 MaxAge 字段。通常,考慮到默認時區問題,本地時間不可靠,推薦通過 MaxAge 字段設置 Cookie 過期時間,不過對于 Web 應用而言,通常不設置過期時間,讓 Cookie 隨著瀏覽器關閉而失效即可。
了解了 Cookie 的基本結構,以及如何在 Go 語言中表示后,我們嘗試在 HTTP 響應中通過設置 Set-Cookie 頭新增 Cookie 并將其發送給客戶端瀏覽器,在此之前的在線論壇項目中,已經在用戶認證時用到了 Cookie 設置:
cookie := http.Cookie{
Name: "_cookie",
Value: session.Uuid,
HttpOnly: true,
Path: "/",
}
http.SetCookie(writer, &cookie)
http.Redirect(writer, request, "/", 302)
上述代碼是在用戶認證通過后將 Session ID 通過 Cookie 存儲到客戶端,以便后續記住用戶登錄狀態,直到用戶關閉瀏覽器(沒有設置過期時間)。通過這段代碼,可以看出要在響應中發送 Cookie,需要先通過 http.Cookie 初始化一個 Cookie 對象,再通過 http.SetCookie 方法將這個 Cookie 寫入到 HTTP 響應中,這樣發送響應給客戶端的時候就會帶上這個 Cookie 了。
接下來,我們在 goblog 項目中演示發送 Cookie 到客戶端,這一次,我們不通過寫入 Cookie 到 HTTP 響應,而是直接通過 HTTP 響應頭 Set-Cookie 來設置 Cookie,在 goblog/handlers/common.go 中新增 SetCookie 處理器:
func SetCookie(w http.ResponseWriter, r *http.Request) {
c1 := http.Cookie{
Name: "username",
Value: url.QueryEscape("學院君"),
HttpOnly: true,
}
c2 := http.Cookie{
Name: "website",
Value: "https://xueyuanjun.com",
HttpOnly: true,
}
w.Header().Add("Set-Cookie", c1.String())
w.Header().Add("Set-Cookie", c2.String())
fmt.Fprintln(w, "通過 HTTP 響應頭發送 Cookie 信息")
}
這里我們新增了兩個 Cookie,所以使用了 w.Header().Add 方法,如果用 Set 方法,后面的 Set-Cookie 頭會覆蓋前面的,另外,由于 Cookie 值包含了中文字符,需要通過 url.QueryEscape 方法進行 URL 編碼,否則無法正常顯示。
在 routes/web.go 中注冊對應的路由:
WebRoute{
"SetCookie",
"GET",
"/setcookies",
handlers.SetCookie,
},
重啟 HTTP 服務器,在瀏覽器中訪問 http://localhost:8080/setcookies,就可以在響應結果中看到對應的 Cookie 信息了:
當然也可以通過 http.SetCookie 方法寫入 Cookie 到 HTTP 響應來實現,對應的代碼如下,這樣做更便捷:
http.SetCookie(w, &c1)
http.SetCookie(w, &c2)
還可以通過 Expires/MaxAge 設置 Cookie 的有效期:
c1 := http.Cookie{
Name: "username",
...
Expires: time.Now().AddDate(0, 0, 1), // Cookie 有效期設置為1天
}
c2 := http.Cookie{
Name: "website",
...
MaxAge: 1000, // Cookie 有效期設置為 1000s
}
這樣,就可以在響應中看到對應的 Cookie 有效期了:
一旦通過 Set-Cookie 響應頭將 Cookie 信息發送到客戶端瀏覽器,那么在 Cookie 有效期內,下次同域名下的用戶請求將自動在請求頭中包含對應的 Cookie 信息,比如我們訪問 http://localhost:8080,就可以在請求頭 Cookie 中看到上次響應返回的 Cookie:
要在服務端獲取這些 Cookie 信息,可以通過讀取請求頭的方式:
cookie := r.Header.Get("Cookie")
但是這種方式讀取的 Cookie 字符串值還需要進行解析,才能得到每個 Cookie 的值,為此可以通過更加便捷的專門用于讀取每個 Cookie 的 r.Cookie 方法(r 表示 HTTP 請求對象實例),我們在 handlers/common.go 中新增一個 GetCookie 方法:
func GetCookie(w http.ResponseWriter, r *http.Request) {
c1, err := r.Cookie("username")
if err != nil {
fmt.Fprintln(w, "名為 username 的 Cookie 不存在")
return
}
username, _ := url.QueryUnescape(c1.Value)
c2, err := r.Cookie("website")
if err != nil {
fmt.Fprintln(w, "名為 website 的 Cookie 不存在")
return
}
website := c2.Value
fmt.Fprintf(w, "從用戶請求中讀取的 Cookie: {username: %s, website: %s}\n", username, website)
}
需要注意的是 r.Cookie 方法返回的是指針類型的 Cookie 對象和一個錯誤信息,需要通過調用 Cookie 對象上的 Value 屬性返回對應的 Cookie 值,對于 username 而言,還需要通過 url.QueryUnescape 對編碼值進行解碼。
在 routes/web.go 中注冊一個對應的路由:
WebRoute{
"GetCookie",
"GET",
"/getcookies",
handlers.GetCookie,
},
然后重啟 HTTP 服務器,在瀏覽器中訪問 http://localhost:8080/getcookies,website Cookie 如果已經過期,則會打印錯誤消息:
重新訪問 http://localhost:8080/setcookies,再訪問 http://localhost:8080/getcookies,就可以成功獲取并打印出所有的 Cookie 信息:
如果想要一次性獲取所有 Cookie,還可以通過 r.Cookies() 方法,該方法會返回的是 Cookie 對象指針類型切片:
cookies := r.Cookies()
c1 := cookies[0] // username=%E5%AD%A6%E9%99%A2%E5%90%9B
c2 := cookies[1] // website=https://xueyuanjun.com
如果想要在 Cookie 過期之前提前刪除 Cookie,可以將 MaxAge 設置為小于 0 的值即可:
c2 := http.Cookie{
Name: "website",
Value: "https://xueyuanjun.com",
HttpOnly: true,
MaxAge: -1, // Cookie 有效期設置為 -1,就會在當前響應發送給客戶端后銷毀該 Cookie
}
如果用 Expires 字段來設置的話,可以設置 Unix 時間戳的值為 1(對應的絕對時間是 1970-01-01 08:00:01 +0800 CST,也就是一個過去的時間):
c2 := http.Cookie{
Name: "website",
Value: "https://xueyuanjun.com",
HttpOnly: true,
Expires: time.Unix(1, 0), // Cookie 有效期設置為過去的時間
}
所謂一次性消息,指的是頁面重新加載后消息就不存在了,也就是該消息只能被讀取一次,不管你用不用它都不復存在了。我們可以結合上面的刪除 Cookie 功能來實現這個一次性消息功能,首先在 common.go 中新增一個 SetWelcomeMessage 處理器:
func SetWelcomeMessage(w http.ResponseWriter, r *http.Request) {
msg := "歡迎訪問學院君網站"
cookie := http.Cookie{
Name: "welcome_message",
Value: base64.URLEncoding.EncodeToString([]byte(msg)),
}
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/get_welcome_message", 302)
}
這里發送 Cookie 到客戶端和前面的新增 Cookie 邏輯完全一樣,最后通過 http.Redirect 將請求重定向到 /get_welcome_message 路由,另外這一次我們通過 Base64 對 Cookie 值進行編碼,因為其中包含中文和特殊字符。接下來我們繼續在 common.go 中編寫 /get_welcome_message 路由對應的處理器 GetWelcomeMessage:
func GetWelcomeMessage(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("welcome_message")
if err != nil {
fmt.Fprintln(w, "沒有在 Cookie 中找到歡迎消息")
} else {
delCookie := http.Cookie{
Name: "welcome_message",
MaxAge: -1,
}
http.SetCookie(w, &delCookie)
msg, _ := base64.URLEncoding.DecodeString(cookie.Value)
fmt.Fprintln(w, string(msg))
}
}
在這段代碼中,首先通過 r.Cookie 方法從 Cookie 中讀取歡迎消息,讀取之后,通過 Base64 對其進行解碼,然后作為響應實體返回給客戶端,這一塊和之前讀取 Cookie 邏輯一樣,只是新增了讀取成功之后,刪除這個 Cookie 的功能。
最后,在 routes/web.go 中注冊上述處理器方法對應的路由:
WebRoute{
"SetMessage",
"GET",
"/set_welcome_message",
handlers.SetWelcomeMessage,
},
WebRoute{
"GetMessage",
"GET",
"/get_welcome_message",
handlers.GetWelcomeMessage,
},
重啟 HTTP 服務器,在瀏覽器中訪問 http://localhost:8080/set_welcome_message,頁面會重定向到 http://localhost:8080/get_welcome_message,然后打印出歡迎消息,說明 Cookie 讀取成功:
如果查看 Chrome 控制臺的話,可以在 Network 標簽頁看到對應的 Cookie 響應頭和請求頭:
在 get_welcome_message 請求頭中可以看到對應的 Cookie,此外這個請求的響應頭還包含了刪除 Cookie 的邏輯:
如果在「Application」標簽頁查看 Cookie 的話,會發現已經沒有 welcome_message 了(website 到了過期時間自動銷毀,所以也看不到了):
好了,關于 HTTP Cookie 功能我們簡單介紹到這里,下篇教程,我們來探討在 Go 語言中如何基于 Cookie 實現 Session 技術。
(全文完)
入我的主頁,查看更多JS的分享!
我的代碼有多短,本篇內容就有多短!
本地存儲對比:
今天不想多說話,直接貼上代碼:
//判斷是否支持 比如瀏覽器開啟了隱私模式
var isCookie=()=>{
return navigator.cookieEnabled;
};
//存儲
function setCookie(cname, cvalue, exdays=0) {
cvalue=encodeURIComponent(JSON.stringify(cvalue));
if (exdays > 0) {
var d=new Date().getTime() + exdays * 24 * 3600 * 1000 + 8 * 3600 * 1000;
var expires="expires=" + new Date(d).toUTCString();
document.cookie=cname + "=" + cvalue + ";" + expires + ";path=/";
} else {
document.cookie=cname + "=" + cvalue + ";" + ";path=/";
}
}
//獲取
function getCookie(cname) {
var name=cname + "=";
var ca=document.cookie.split(";");
for (var i=0; i < ca.length; i++) {
var c=ca[i];
while (c.charAt(0)==" ") {
c=c.substring(1);
}
if (c.indexOf(name)==0) {
let d=c.substring(name.length, c.length);
return JSON.parse(decodeURIComponent(d));
}
}
return "";
}
//獲取 通過正則
// function getCookie(name) {
// var arr,
// reg=new RegExp("(^| )" + name + "=([^;]*)(;|$)");
// if ((arr=document.cookie.match(reg))) {
// return JSON.parse(decodeURIComponent(arr[2]));
// } else {
// return null;
// }
// }
//刪除
function deleteCookie(name) {
var date=new Date();
date.setTime(date.getTime() - 1);
var delValue=getCookie(name);
if (delValue) {
document.cookie=name + "=" + delValue + ";expires=" + date.toGMTString();
}
}
使用示例:
//定義key
const tk="tk2020";
const uk="uk2020";
//保存
setCookie(tk, "14332239527007001", 0);
setCookie(uk, { id: 1, name: "以氣御碼" }, 0);
//獲取
let token=getCookie(tk);
let user=getCookie(uk);
console.log(token);
console.log(user);
當使用setCookie時,傳0或不傳,表示關閉瀏覽器后就被清除,截圖預覽:
當登錄的信息存儲為這種形式,可以實現關閉瀏覽器,就清除登錄信息。也可以再配合登錄有效期,總不能“只要不關瀏覽器,就不退出登錄了”。
文檔:
有補充請在評論區留言。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。