天天看點

【Go Web學習筆記】第八章 Go與Cookie

前言:大家好,以下所有内容都是我學習韓茹老師的教程時所整理的筆記。部分内容有過删改, 推薦大家去看原作者的文檔進行學習, 本文章僅作為個人的學習筆記,後續還會在此基礎上不斷修改。學習Go Web時應該已經熟悉Go語言基本文法以及計算機網絡的相關内容。

學習連結:https://www.chaindesk.cn/witbook/17/253

參考書籍:《Go Web程式設計》謝孟軍

第八章、cookie

Web開發中一個很重要的議題就是如何做好使用者的整個浏覽過程的控制,因為HTTP協定是無狀态的,是以使用者的每一次請求都是無狀态的,我們不知道在整個Web操作過程中哪些連接配接與該使用者有關,我們應該如何來解決這個問題呢?Web裡面經典的解決方案是cookie和session,cookie機制是一種用戶端機制,把使用者資料儲存在用戶端,而session機制是一種伺服器端的機制,伺服器使用一種類似于散清單的結構來儲存資訊,每一個網站訪客都會被配置設定給一個唯一的标志符, 即sessionID, 它的存放形式無非兩種: 要麼經過 url 傳遞,要麼儲存在用戶端的cookies裡。當然,你也可以将Session儲存到資料庫裡,這樣會更安全,但效率方面會有所下降。

1、cookie的介紹

session和cookie是網站浏覽中較為常見的兩個概念,也是比較難以辨析的兩個概念,但它們在浏覽需要認證的服務頁面以及頁面統計中卻相當關鍵。我們先來了解一下cookie怎麼來的?考慮這樣一個問題:

如何抓取一個通路受限的網頁?如新浪微網誌好友的首頁,個人微網誌頁面等。

顯然,通過浏覽器,我們可以手動輸入使用者名和密碼來通路頁面,而所謂的“抓取”,其實就是使用程式來模拟完成同樣的工作,是以我們需要了解“登陸”過程中到底發生了什麼。

當使用者來到微網誌登陸頁面,輸入使用者名和密碼之後點選“登入”後浏覽器将認證資訊POST給遠端的伺服器,伺服器執行驗證邏輯,如果驗證通過,則浏覽器會跳轉到登入使用者的微網誌首頁,在登入成功後,伺服器如何驗證我們對其他受限制頁面的通路呢?因為HTTP協定是無狀态的,是以很顯然伺服器不可能知道我們已經在上一次的HTTP請求中通過了驗證。當然,最簡單的解決方案就是所有的請求裡面都帶上使用者名和密碼,這樣雖然可行,但大大加重了伺服器的負擔(對于每個request都需要到資料庫驗證),也大大降低了使用者體驗(每個頁面都需要重新輸入使用者名密碼,每個頁面都帶有登入表單)。既然直接在請求中帶上使用者名與密碼不可行,那麼就隻有在伺服器或用戶端儲存一些類似的可以代表身份的資訊了,是以就有了cookie與session。

cookie,簡而言之就是在本地計算機儲存一些使用者操作的曆史資訊(當然包括登入資訊),并在使用者再次通路該站點時浏覽器通過HTTP協定将本地cookie内容發送給伺服器,進而完成驗證,或繼續上一步操作。

cookie的原理圖:

【Go Web學習筆記】第八章 Go與Cookie

Cookie是由浏覽器維持的,存儲在用戶端的一小段文本資訊,伴随着使用者請求和頁面在Web伺服器和浏覽器之間傳遞。使用者每次通路站點時,Web應用程式都可以讀取cookie包含的資訊。浏覽器設定裡面有cookie隐私資料選項,打開它,可以看到很多已通路網站的cookies,如下圖所示:

【Go Web學習筆記】第八章 Go與Cookie

cookie是有時間限制的,根據生命期不同分成兩種:會話cookie和持久cookie;

如果不設定過期時間,則表示這個cookie生命周期為從建立到浏覽器關閉止,隻要關閉浏覽器視窗,cookie就消失了。這種生命期為浏覽會話期的cookie被稱為會話cookie。會話cookie一般不儲存在硬碟上而是儲存在記憶體裡。

如果設定了過期時間(setMaxAge(606024)),浏覽器就會把cookie儲存到硬碟上,關閉後再次打開浏覽器,這些cookie依然有效直到超過設定的過期時間。存儲在硬碟上的cookie可以在不同的浏覽器程序間共享,比如兩個IE視窗。而對于儲存在記憶體的cookie,不同的浏覽器有不同的處理方式。

2、Go使用cookie

Go語言中通過net/http包中的SetCookie來設定:

w表示需要寫入的response,cookie是一個struct,讓我們來看一下cookie對象是怎麼樣的

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
    Raw      string
    Unparsed []string // Raw text of unparsed attribute-value pairs
}
           

我們來看一個例子,如何設定cookie,以及擷取cookie

package main

import (
    "net/http"
    "fmt"
)

func main() {
    http.HandleFunc("/setcookie", SetCookie)
    http.HandleFunc("/getcookie", GetCookie)
    http.ListenAndServe("localhost:8080", nil)
}

func SetCookie(w http.ResponseWriter, r *http.Request) {
    //設定cookie
    cookie := http.Cookie{Name: "name", Value: "hanru", Path: "/", MaxAge: 60}
    http.SetCookie(w, &cookie)
    w.Write([]byte("write cookie ok"))
}

//Go讀取cookie
func GetCookie(w http.ResponseWriter, r *http.Request) {
    cookie2, _ := r.Cookie("name")
    fmt.Fprint(w, cookie2)
    //還有另外一種讀取方式
    //for _, cookie := range r.Cookies() {
    //  fmt.Fprint(w, cookie.Name)
    //}
}
           

運作伺服器後,打開浏覽器輸入位址:http://127.0.0.1:8080/setcookie

運作結果如下:

【Go Web學習筆記】第八章 Go與Cookie

在chrome浏覽器中執行:http://127.0.0.1:8080/setcookie, 觸發go服務執行設定cookie的動作, 浏覽器收到這個資訊後, 真正執行設定cookie, 在chrome中可查(chrome://settings/content/cookies目錄中的localhost域名中查), 如下:

【Go Web學習筆記】第八章 Go與Cookie

可以看到,過期時間是60s, 60s後再次查的時候, 就沒有name對應的cookie項了。

接下來,我們擷取一下cookie,要在設定cookie的60s内進行擷取,否則就取不到了。

然後打開浏覽器,輸入網址:http://127.0.0.1:8080/getcookie

運作效果如下:

【Go Web學習筆記】第八章 Go與Cookie

60s後再次運作:

【Go Web學習筆記】第八章 Go與Cookie

我們等cookie過期消失, 然後再來玩抓包。 好,現在沒有name對應的cookie了, 我們連續兩次執行:http://127.0.0.1:8080/setcookie, 服務端tcpdump抓包,兩次的請求和響應依次如下:

第一次:

【Go Web學習筆記】第八章 Go與Cookie

第二次( 必須在60s之内發起請求 ):

【Go Web學習筆記】第八章 Go與Cookie

可以看到,第一次請求時, 浏覽器發出的請求中不帶cookie, 因為浏覽器壓根就沒有這項cookie, 在go服務端的回包中攜帶了Set-Cookie首部, 浏覽器收到這個資訊後,将其寫入到浏覽器本地, 形成cookie。

第二次請求時(因cookie的過期時間設定為了60s, 故必須在60s内發起第二次請求), 此時, 浏覽器的http請求中自動攜帶了cookie資訊,go服務端也能收到這個資訊。

由此可見, cookie不過是浏覽器端的一個環境變量而已, 僅此而已。cookie值存在于浏覽器所在的本地電腦中。 而所謂的服務端設定cookie, 其實是服務端給浏覽器發送對應的設定cookie資訊, 由浏覽器來真正執行設定cookie的操作, 存于本地電腦磁盤中。