Go Cookie

  • HTTP無狀態(tài)協(xié)議

HTTP本身是一種無狀態(tài)的連接協(xié)議,因此每個(gè)請(qǐng)求或響應(yīng)都是獨(dú)立的。服務(wù)端每次處理完一個(gè)客戶端請(qǐng)求之后就會(huì)斷開連接,所以每次請(qǐng)求或響應(yīng)與之前和之后的請(qǐng)求或響應(yīng)是沒有任何關(guān)系的。換句話說,HTTP自身不具備保存之前發(fā)送過的請(qǐng)求或響應(yīng)的狀態(tài)。

由于HTTP無狀態(tài)的特性,在Web應(yīng)用中跟蹤用戶狀態(tài)的方法可分為四種:

  • 建立包含有跟蹤數(shù)據(jù)的隱藏字段
  • 重寫包含額外參數(shù)的URL
  • 使用持續(xù)的Cookie
  • 使用服務(wù)端的Session

Cookie和Session是Web應(yīng)用比較常見的概念,它們的目的都是為了克服HTTP協(xié)議的無狀態(tài)問題。

Cookie

Cookie是一小段由客戶端保存在本地的文本文件,可記錄用戶ID、密碼、瀏覽過的網(wǎng)頁、瀏覽時(shí)間等信息。當(dāng)客戶端再次訪問同一個(gè)網(wǎng)站時(shí),客戶端會(huì)把請(qǐng)求連同Cookie一起發(fā)送給服務(wù)端,服務(wù)端通過檢查Cookie以辨認(rèn)用戶狀態(tài)。

Cookie機(jī)制

Cookie是由服務(wù)端生成后發(fā)送給User-Agent(比如瀏覽器),User-Agent會(huì)將Cookie的key/value保存到本地磁盤上指定目錄下的文本文件內(nèi)。當(dāng)下次請(qǐng)求相同網(wǎng)站時(shí)會(huì)發(fā)送該Cookie給i服務(wù)器,不過前提是瀏覽器必須提前設(shè)置了啟用Cookie。

Cookie的key/value鍵和值可以由服務(wù)端自行定義,這樣服務(wù)端可知道對(duì)應(yīng)用戶是否合法以及是否需要重新登錄等。服務(wù)器可設(shè)置或讀取Cookie中包含的信息,借此來維護(hù)用戶更服務(wù)端會(huì)話的狀態(tài)。

Cookie是HTTP協(xié)議頭的一部分,用戶瀏覽器和服務(wù)器之間傳遞數(shù)據(jù)。當(dāng)客戶端第一次向服務(wù)器發(fā)起請(qǐng)求時(shí),服務(wù)端會(huì)創(chuàng)建一個(gè)Cookie,并通過HTTP響應(yīng)頭中的Set-Cookie屬性將Cookie信息返回給客戶端,并通知客戶端保存。

Cookie

Cookie的傳遞流程

  1. 客戶端首次發(fā)送請(qǐng)求,此時(shí)請(qǐng)求報(bào)文中沒有Cookie信息。
GET /index HTTP/1.1
Host: www.baidu.com
  1. 服務(wù)端收到請(qǐng)求后生成Cookie信息,同時(shí)發(fā)送響應(yīng)報(bào)文。
HTTP/1.1 200 OK
Server: Apache
<Set-Cookie: sid=57111807181018; path=/;expires=Web,10-OCT-12 07:12:20 GMT>
Content-Type: text/plain; charset=UTF-8
  1. 客戶端再次向服務(wù)端發(fā)起請(qǐng)求報(bào)文,此時(shí)會(huì)自動(dòng)發(fā)送保存的Cookie信息。
GET /image/ HTTP1.1
HOST: www.baidu.com
Cookie: sid=57111807181018

Cookie中主要包含NAME(名稱)、path(路徑)、domain(域名)、expires(有效期)、max-age(過期時(shí)間)等屬性。

Cookie是針對(duì)單個(gè)域名domain的,因此不同域名之間的Cookie是相互獨(dú)立的。

通過設(shè)置Cookie的maxAge屬性可以設(shè)置Cookie的過期時(shí)間,若不設(shè)置maxAge則被成為會(huì)話Cookie,會(huì)話Cookie的生命周期從瀏覽器打開到關(guān)閉為止,主要關(guān)閉瀏覽器窗口,會(huì)話Cookie就會(huì)消失。會(huì)話Cookie一般保存在內(nèi)存而非磁盤。

通過設(shè)置過期時(shí)間(setMaxAge(606024)),瀏覽器會(huì)將Cookie保存在本地磁盤中,對(duì)于關(guān)閉后重新打開的瀏覽器,這些Cookie依舊有效。

Cookie過期時(shí)間的設(shè)置方式

cookie.setMaxAge(0); //不記錄Cookie
cookie.setMaxAge(-1);//會(huì)話級(jí)Cookie,關(guān)閉瀏覽器后立即失效。
cookie.setMaxAge(60 * 60);//過期時(shí)間設(shè)置為1小時(shí)

Go Cookie

Go語言標(biāo)準(zhǔn)庫net/http中定義了Cookie的數(shù)據(jù)結(jié)構(gòu),用于表示一個(gè)出現(xiàn)在HTTP響應(yīng)頭Set-Cookie的值或HTTP請(qǐng)求頭中Cookie的值。

Cookie的數(shù)據(jù)結(jié)構(gòu)

type Cookie struct{
    Name string
    Value string

    Path string
    Domain string
    Expires time.Time
    RawExpires string

    MaxAge int
    Secure bool
    HttpOnly bool
    Raw string
    Unparsed []string
}
字段 描述
Expires Cookie過期時(shí)間,使用絕對(duì)時(shí)間,比如2020/12/21 00:00:00。
MaxAge Cookie的最大生存秒數(shù)時(shí)長,使用相對(duì)時(shí)間,比如300秒。
Secure Cookie是否需要安全傳輸,當(dāng)為真時(shí)表示只有HTTPS才會(huì)傳輸該Cookie。
HttpOnly Cookie是否能夠被JavaScripit讀取其值
Unparsed 表示未解析的鍵值對(duì)的原始文本

沒有設(shè)置Expires字段的Cookie稱為會(huì)話Cookie或臨時(shí)Cookie,這種Cookie在瀏覽器窗口關(guān)閉時(shí)會(huì)自動(dòng)刪除。設(shè)置了Expires字段的Cookie稱為持久Cookie,這種Cookie會(huì)一直存在,直到指定時(shí)間到期或手動(dòng)刪除。

Expires和MaxAge都可以用于設(shè)置Cookie的過期時(shí)間,Expires字段設(shè)置的Cookie在指定時(shí)間點(diǎn)過期,MaxAge字段設(shè)置的是Cookie自創(chuàng)建之后能夠存活多少秒。雖然HTTP 1.1中廢棄了Expires并推薦使用MaxAge代替,但幾乎所有瀏覽器仍然支持Expires。微軟的IE6/IE7/IE8并不支持MaxAge。為了更好地移植性,優(yōu)先推薦使用Expires。

最大存活期MaxAge取值范圍

MaxAge 描述
0 表示尚未設(shè)置Max-Age屬性
<0 表示立即刪除Cookie,等價(jià)于Max-Age:0。
>0 表示存在Max-Age屬性,且單位為秒。

獲取Cookie

Request對(duì)象中擁有兩個(gè)獲取Cookie的方法和一個(gè)添加Cookie的方法

  • 解析并返回請(qǐng)求的Cookie頭設(shè)置的所有Cookie
func (r *Request) Cookies() []*Cookie
  • 返回請(qǐng)求中名為name的Cookie,若未找到則會(huì)返回nilErrNoCookie。
func (r *Request) Cookie(name string) (*Cookie, error)

例如:

cookie := http.Cookie{Name:"username", Value:"junchow", Expires:expiration}
  • 添加Cookie可通過AddCookie方法向請(qǐng)求中添加一個(gè)Cookie
func (r *Request) AddCookie(c *Cookie)

設(shè)置Cookie

Go語言中設(shè)置Cookie是通過net/http標(biāo)準(zhǔn)包中的SetCookie函數(shù)實(shí)現(xiàn)的,它會(huì)在responseWriter的頭域中添加Set-Cookie頭,其值為cookie

http.SetCookie(responseWriter, &cookie)

例如:在HTTP響應(yīng)中通過設(shè)置Set-Cookie頭新增Cookie并將其發(fā)送給客戶端瀏覽器

package main

import (
    "fmt"
    "net/http"
    "time"
)

func indexHandler(responseWriter http.ResponseWriter, request *http.Request) {
    //獲取Cookie
    cookie,err := request.Cookie("sessionid")
    if cookie == nil && err != nil {
        expires := time.Now().Add(time.Hour)
        //設(shè)置Cookie
        cookie := &http.Cookie{
            Name:"sessionid",
            Value:"1jl3dndo0ex82kal",
            MaxAge:60*60,
            Expires: expires,
            Domain:"127.0.0.1:9090",
            Path:"/",
            HttpOnly:true,
        }
        http.SetCookie(responseWriter, cookie)
    }else{
        //cookie:(*http.Cookie)(nil), err:http: named cookie not present
        fmt.Printf("cookie:%#v, err:%v\n", cookie, err)
    }

    responseWriter.Write([]byte("hello"))
}

func main() {
    http.HandleFunc("/", indexHandler)
    http.ListenAndServe("0.0.0.0:9090", nil)
}

查看請(qǐng)求

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7
Cache-Control: max-age=0
Connection: keep-alive
Cookie: sessionid=1jl3dndo0ex82kal
Host: 127.0.0.1:9090
sec-ch-ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36

例如:直接通過HTTP響應(yīng)頭Set-Cookie來設(shè)置Cookie

package main

import (
    "fmt"
    "net/http"
    "net/url"
)

func indexHandler(responseWriter http.ResponseWriter, request *http.Request) {
    cookie := http.Cookie{
        Name:"account",
        Value:url.QueryEscape("junchow"),
        HttpOnly:true,
    }
    responseWriter.Header().Add("Set-Cookie", cookie.String())
    fmt.Fprintln(responseWriter, "hello world")
}

func main() {
    http.HandleFunc("/", indexHandler)
    http.ListenAndServe("0.0.0.0:9090", nil)
}

查看HTTP響應(yīng)頭

Content-Length: 12
Content-Type: text/plain; charset=utf-8
Date: Fri, 22 Jan 2021 19:44:31 GMT
Set-Cookie: account=junchow; HttpOnly
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是session?什么是cookie?session和cookie有什么區(qū)別?什么場景適用于session?什...
    兮_eeb8閱讀 3,954評(píng)論 1 24
  • 關(guān)鍵詞:cookie session token 一、什么是cookie HTTP 是無狀態(tài)的協(xié)議...
    Jeff_9021閱讀 533評(píng)論 0 0
  • cookie cookie的起源 早期web剛開始出現(xiàn)復(fù)雜的應(yīng)用程序時(shí),產(chǎn)生了對(duì)于能夠直接在客戶端上存儲(chǔ)用戶信息能...
    zenggo閱讀 4,008評(píng)論 1 52
  • 久違的晴天,家長會(huì)。 家長大會(huì)開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,819評(píng)論 16 22
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    余生動(dòng)聽閱讀 10,849評(píng)論 0 11

友情鏈接更多精彩內(nèi)容