Go語(yǔ)言讀取,設(shè)置Cookie及設(shè)置cookie過(guò)期方法詳解
Cookie用來(lái)解決http協(xié)議無(wú)狀態(tài)的問(wèn)題。
首先,在服務(wù)端生成Cookie,然后在http響應(yīng)header中設(shè)置Set-Cookie字段,客戶端會(huì)讀取到Set-Cookie字段后,會(huì)將cookie信息存儲(chǔ)起來(lái),下次繼續(xù)訪問(wèn)服務(wù)端時(shí),會(huì)在http請(qǐng)求中設(shè)置Cookie字段并發(fā)送給服務(wù)端,服務(wù)端可以解析這個(gè)Cookie字段,從而知道這個(gè)客戶端之前已經(jīng)和自己有過(guò)會(huì)話(上下文),然后再執(zhí)行相應(yīng)的邏輯代碼。
Cookie分為兩種類型:session cookie和persistent cookie。
- Session Cookie也稱為臨時(shí)Cookie,客戶端只會(huì)將cookie數(shù)據(jù)存儲(chǔ)在http client進(jìn)程的內(nèi)容中,不會(huì)保存到磁盤文件中(或其它存儲(chǔ)設(shè)備),瀏覽器關(guān)閉(或者說(shuō)http client進(jìn)程退出)的時(shí)候,cookie就刪除了。
- persistent cookie是持久化cookie,瀏覽器退出也不刪除,而是根據(jù)服務(wù)端發(fā)送cookie時(shí)設(shè)置的過(guò)期時(shí)長(zhǎng)判斷cookie是否過(guò)期,只要cookie還有效,客戶端就會(huì)攜帶cookie訪問(wèn)服務(wù)端。
Cookie struct
$ go doc http.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 } func (c *Cookie) String() string
一個(gè)Cookie代表一個(gè)http cookie。服務(wù)端可以設(shè)置多個(gè)Set-Cookie字段發(fā)送給客戶端。。
Name和Value分別設(shè)置這個(gè)cookie的key/value。一定要有至少一個(gè)能唯一區(qū)分客戶端的ID類的value。
Expires指定cookie到什么時(shí)候過(guò)期,是一個(gè)時(shí)間值。當(dāng)指定為過(guò)去的時(shí)間值時(shí),表示這個(gè)cookie已經(jīng)過(guò)期。
MaxAge也用來(lái)設(shè)置cookie什么時(shí)候過(guò)期,MaxAge為負(fù)數(shù)或等于0表示立即過(guò)期,MaxAge大于0表示過(guò)多少秒之后過(guò)期。
MaxAge和Expires都可以設(shè)置cookie持久化時(shí)的過(guò)期時(shí)長(zhǎng),Expires是老式的過(guò)期方法,如果可以,應(yīng)該使用MaxAge設(shè)置過(guò)期時(shí)間,但有些老版本的瀏覽器不支持MaxAge。如果要支持所有瀏覽器,要么使用Expires,要么同時(shí)使用MaxAge和Expires。
Path和Domain設(shè)置訪問(wèn)哪些路徑或域名范圍的主機(jī)時(shí)應(yīng)該攜帶這個(gè)cookie。如果不設(shè)置,則訪問(wèn)所有路徑、該Domain下的主機(jī)都攜帶cookie。
cookie.Path("/WEB16"); 代表訪問(wèn)WEB16應(yīng)用中的任何資源都攜帶cookie cookie.Path("/WEB16/cookietest"); 代表訪問(wèn)WEB16中的cookietest時(shí)才攜帶cookie信息 cookie.Domain(".foo.com"); 這對(duì)foo.com域下的所有主機(jī)都生效(如www.foo.com),但不包括子域www.abc.foo.com
Secure和HttpOnly字段為cookie提供一些保護(hù)機(jī)制。這兩個(gè)cookie屬性的介紹,參見(jiàn):
Cookie有一個(gè)String()方法,用來(lái)將Cookie實(shí)例轉(zhuǎn)換成字符串。轉(zhuǎn)化成字符串之后就可以直接設(shè)置在Header中。
例如,下面是登錄youtube的時(shí)候,對(duì)方發(fā)送給我的cookie:
設(shè)置Cookie并發(fā)送給客戶端
package main import ( "fmt" "net/http" ) func setCookie(w http.ResponseWriter, r *http.Request) { // 定義兩個(gè)cookie c1 := http.Cookie{ Name: "first_cookie", Value: "Go Programming", } c2 := http.Cookie{ Name: "second_cookie", Value: "Go Web Programming", HttpOnly: true, } // 設(shè)置Set-Cookie字段 w.Header().Set("Set-Cookie", c1.String()) w.Header().Add("Set-Cookie", c2.String()) fmt.Fprintf(w, "%s\n%s\n", c1.String(), c2.String()) } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/set_cookie", setCookie) server.ListenAndServe() }
訪問(wèn)http://127.0.0.1:8080/set_cookie
時(shí),查看Header將顯式Set-Cookie字段。
$ curl -i http://127.0.0.1:8080/set_cookie HTTP/1.1 200 OK Set-Cookie: first_cookie="Go Programming" Set-Cookie: second_cookie="Go Web Programming"; HttpOnly Date: Tue, 27 Nov 2018 10:12:44 GMT Content-Length: 75 Content-Type: text/plain; charset=utf-8 first_cookie="Go Programming" second_cookie="Go Web Programming"; HttpOnly
http包提供了一個(gè)SetCookie()函數(shù),可以直接用來(lái)設(shè)置Set-Cookie字段。
func SetCookie(w ResponseWriter, cookie *Cookie)
注意,第二個(gè)字段是指針類型的Cookie。
修改前面的示例,使用SetCookie()函數(shù)發(fā)送Set-Cookie字段:
func setCookie(w http.ResponseWriter, r *http.Request) { c1 := http.Cookie{ Name: "first_cookie", Value: "Go Programming", } c2 := http.Cookie{ Name: "second_cookie", Value: "Go Web Programming", HttpOnly: true, } http.SetCookie(w, &c1) http.SetCookie(w, &c2) }
取得客戶端攜帶的cookie
由于客戶端發(fā)起請(qǐng)求時(shí),如果攜帶cookie,是直接放在Request的Cookie Header中的。所以,可以通過(guò)Request取得客戶端攜帶的cookie信息。當(dāng)然,也可以通過(guò)Request的方法Cookie()或Cookies()取得cookie信息。
func (r *Request) Cookie(name string) (*Cookie, error) func (r *Request) Cookies() []*Cookie
- Cookie(Name)只取某個(gè)cookie
- Cookies()取所有的cookie
下面是通過(guò)Request Header的方式取Cookie的示例:
package main import ( "fmt" "net/http" ) func setCookie(w http.ResponseWriter, r *http.Request) { c1 := http.Cookie{ Name: "first_cookie", Value: "Go Programming", } c2 := http.Cookie{ Name: "second_cookie", Value: "Go Web Programming", HttpOnly: true, } http.SetCookie(w, &c1) http.SetCookie(w, &c2) } func getCookie(w http.ResponseWriter, r *http.Request) { cookie := r.Header.Get("Cookie") fmt.Fprintf(w, "%s\n", cookie) } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/set_cookie", setCookie) http.HandleFunc("/get_cookie", getCookie) server.ListenAndServe() }
在訪問(wèn)http://127.0.0.1:8080/set_cookie
之后不要關(guān)閉瀏覽器,再次訪問(wèn)http://127.0.0.1:8080/get_cookie
,將輸出:
first_cookie="Go Programming"; second_cookie="Go Web Programming"
或者,使用curl記錄cookie,并下次訪問(wèn)時(shí)讀取cookie:
$ curl -c a.cookie http://127.0.0.1:8080/set_cookie $ curl -b a.cookie http://127.0.0.1:8080/get_cookie first_cookie="Go Programming"; second_cookie="Go Web Programming"
下面是改用Request的Cookie()和Cookies()方法取cookie:
func getCookie(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("first_cookie") if err != nil { fmt.Fprintf(w, "Cat't get Cookie") } cookies := r.Cookies() fmt.Fprintf(w, "%s\n%s\n", cookie, cookies) }
訪問(wèn)結(jié)果:
$ curl -c a.cookie http://127.0.0.1:8080/set_cookie $ curl -b a.cookie http://127.0.0.1:8080/get_cookie first_cookie="Go Programming" [first_cookie="Go Programming" second_cookie="Go Web Programming"]
設(shè)置cookie過(guò)期示例:發(fā)送臨時(shí)消息
有時(shí)候可能想要讓客戶端的某些操作只顯示一次相關(guān)消息,例如post一篇帖子失敗后,應(yīng)該顯示失敗信息,但下次再訪問(wèn)不應(yīng)該再顯示這些失敗信息。
通過(guò)設(shè)置cookie過(guò)期的技巧,可以實(shí)現(xiàn)一些一次性操作。設(shè)置cookie過(guò)期的方式是設(shè)置MaxAge為負(fù)數(shù)或0,為了兼容所有瀏覽器,可以設(shè)置Expires為過(guò)去的一段時(shí)間。
下面的示例中,將一段數(shù)據(jù)使用URL格式編碼后作為flash cookie的值。當(dāng)客戶端訪問(wèn)set_message的時(shí)候,就會(huì)在http Client進(jìn)程中保存這段cookie。再訪問(wèn)show_message的時(shí)候,handler解析客戶端攜帶的cookie,并設(shè)置一個(gè)Set-Cookie字段,這個(gè)字段的作用是使之前保存的cookie過(guò)期。然后輸出解碼后客戶端攜帶的cookie的值。再次刷新show_message,將得到不同的輸出結(jié)果。
package main import ( "encoding/base64" "fmt" "net/http" "time" ) func set_message(w http.ResponseWriter, r *http.Request) { msg := []byte("Hello World") cookie := http.Cookie{ Name: "flash", Value: base64.URLEncoding.EncodeToString(msg), } http.SetCookie(w, &cookie) } func show_message(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("flash") if err != nil { if err == http.ErrNoCookie { fmt.Fprintln(w, "no messages to show") } } else { expire_cookie := http.Cookie{ Name: "flash", MaxAge: -1, Expires: time.Unix(1, 0), } http.SetCookie(w, &expire_cookie) value, _ := base64.URLEncoding.DecodeString(cookie.Value) fmt.Fprintln(w, string(value)) } } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/set_message", set_message) http.HandleFunc("/show_message", show_message) server.ListenAndServe() }
使用curl測(cè)試。注意,首先訪問(wèn)set_message的時(shí)候,保存cookie到b.cookie文件。再訪問(wèn)show_message的時(shí)候,也要帶上-c b.cookie
將已保存的cookie設(shè)置為過(guò)期,之后再訪問(wèn)show_message就會(huì)出現(xiàn)預(yù)期的結(jié)果:
$ curl -c b.cookie http://127.0.0.1:8080/set_message $ curl -b b.cookie -c b.cookie http://127.0.0.1:8080/show_message Hello World $ curl -b b.cookie -c b.cookie http://127.0.0.1:8080/show_message no messages to show
相關(guān)文章
Go語(yǔ)言學(xué)習(xí)之golang-jwt/jwt的教程分享
jwt是?json?web?token的簡(jiǎn)稱。go使用jwt目前,主流使用的jwt庫(kù)是golang-jwt/jwt。本文就來(lái)和大家講講golang-jwt/jwt的具體使用,需要的可以參考一下2023-01-01HTTP服務(wù)壓力測(cè)試工具及相關(guān)術(shù)語(yǔ)講解
這篇文章主要為大家介紹了HTTP服務(wù)壓力測(cè)試工具使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04go實(shí)現(xiàn)圖片拼接與文字書寫的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于go實(shí)現(xiàn)圖片拼接與文字書寫的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01淺談Golang 嵌套 interface 的賦值問(wèn)題
這篇文章主要介紹了淺談Golang 嵌套 interface 的賦值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04Golang中的自定義類型之間的轉(zhuǎn)換的實(shí)現(xiàn)(type conversion)
這篇文章主要介紹了Golang中的自定義類型之間的轉(zhuǎn)換的實(shí)現(xiàn)(type conversion),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02golang利用函數(shù)閉包實(shí)現(xiàn)簡(jiǎn)單的中間件
中間件設(shè)計(jì)模式是一種常見(jiàn)的軟件設(shè)計(jì)模式,它在許多編程語(yǔ)言和框架中被廣泛應(yīng)用,這篇文章主要為大家介紹一下golang利用函數(shù)閉包實(shí)現(xiàn)一個(gè)簡(jiǎn)單的中間件,感興趣的可以了解下2023-10-10go語(yǔ)言 xorm框架 postgresql 的用法及詳細(xì)注解
這篇文章主要介紹了go語(yǔ)言 xorm框架 postgresql 的用法及詳細(xì)注解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12