Go Cookie

  • HTTP无状态协议

HTTP本身是一种无状态的连接协议,因此每个请求或响应都是独立的。服务端每次处理完一个客户端请求之后就会断开连接,所以每次请求或响应与之前和之后的请求或响应是没有任何关系的。换句话说,HTTP自身不具备保存之前发送过的请求或响应的状态。

由于HTTP无状态的特性,在Web应用中跟踪用户状态的方法可分为四种:

  • 建立包含有跟踪数据的隐藏字段
  • 重写包含额外参数的URL
  • 使用持续的Cookie
  • 使用服务端的Session

Cookie和Session是Web应用比较常见的概念,它们的目的都是为了克服HTTP协议的无状态问题。

Cookie

Cookie是一小段由客户端保存在本地的文本文件,可记录用户ID、密码、浏览过的网页、浏览时间等信息。当客户端再次访问同一个网站时,客户端会把请求连同Cookie一起发送给服务端,服务端通过检查Cookie以辨认用户状态。

Cookie机制

Cookie是由服务端生成后发送给User-Agent(比如浏览器),User-Agent会将Cookie的key/value保存到本地磁盘上指定目录下的文本文件内。当下次请求相同网站时会发送该Cookie给i服务器,不过前提是浏览器必须提前设置了启用Cookie。

Cookie的key/value键和值可以由服务端自行定义,这样服务端可知道对应用户是否合法以及是否需要重新登录等。服务器可设置或读取Cookie中包含的信息,借此来维护用户更服务端会话的状态。

Cookie是HTTP协议头的一部分,用户浏览器和服务器之间传递数据。当客户端第一次向服务器发起请求时,服务端会创建一个Cookie,并通过HTTP响应头中的Set-Cookie属性将Cookie信息返回给客户端,并通知客户端保存。

Cookie

Cookie的传递流程

  1. 客户端首次发送请求,此时请求报文中没有Cookie信息。
GET /index HTTP/1.1
Host: www.baidu.com
  1. 服务端收到请求后生成Cookie信息,同时发送响应报文。
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. 客户端再次向服务端发起请求报文,此时会自动发送保存的Cookie信息。
GET /image/ HTTP1.1
HOST: www.baidu.com
Cookie: sid=57111807181018

Cookie中主要包含NAME(名称)、path(路径)、domain(域名)、expires(有效期)、max-age(过期时间)等属性。

Cookie是针对单个域名domain的,因此不同域名之间的Cookie是相互独立的。

通过设置Cookie的maxAge属性可以设置Cookie的过期时间,若不设置maxAge则被成为会话Cookie,会话Cookie的生命周期从浏览器打开到关闭为止,主要关闭浏览器窗口,会话Cookie就会消失。会话Cookie一般保存在内存而非磁盘。

通过设置过期时间(setMaxAge(606024)),浏览器会将Cookie保存在本地磁盘中,对于关闭后重新打开的浏览器,这些Cookie依旧有效。

Cookie过期时间的设置方式

cookie.setMaxAge(0); //不记录Cookie
cookie.setMaxAge(-1);//会话级Cookie,关闭浏览器后立即失效。
cookie.setMaxAge(60 * 60);//过期时间设置为1小时

Go Cookie

Go语言标准库net/http中定义了Cookie的数据结构,用于表示一个出现在HTTP响应头Set-Cookie的值或HTTP请求头中Cookie的值。

Cookie的数据结构

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过期时间,使用绝对时间,比如2020/12/21 00:00:00。
MaxAge Cookie的最大生存秒数时长,使用相对时间,比如300秒。
Secure Cookie是否需要安全传输,当为真时表示只有HTTPS才会传输该Cookie。
HttpOnly Cookie是否能够被JavaScripit读取其值
Unparsed 表示未解析的键值对的原始文本

没有设置Expires字段的Cookie称为会话Cookie或临时Cookie,这种Cookie在浏览器窗口关闭时会自动删除。设置了Expires字段的Cookie称为持久Cookie,这种Cookie会一直存在,直到指定时间到期或手动删除。

Expires和MaxAge都可以用于设置Cookie的过期时间,Expires字段设置的Cookie在指定时间点过期,MaxAge字段设置的是Cookie自创建之后能够存活多少秒。虽然HTTP 1.1中废弃了Expires并推荐使用MaxAge代替,但几乎所有浏览器仍然支持Expires。微软的IE6/IE7/IE8并不支持MaxAge。为了更好地移植性,优先推荐使用Expires。

最大存活期MaxAge取值范围

MaxAge 描述
0 表示尚未设置Max-Age属性
<0 表示立即删除Cookie,等价于Max-Age:0
>0 表示存在Max-Age属性,且单位为秒。

获取Cookie

Request对象中拥有两个获取Cookie的方法和一个添加Cookie的方法

  • 解析并返回请求的Cookie头设置的所有Cookie
func (r *Request) Cookies() []*Cookie
  • 返回请求中名为name的Cookie,若未找到则会返回nilErrNoCookie
func (r *Request) Cookie(name string) (*Cookie, error)

例如:

cookie := http.Cookie{Name:"username", Value:"junchow", Expires:expiration}
  • 添加Cookie可通过AddCookie方法向请求中添加一个Cookie
func (r *Request) AddCookie(c *Cookie)

设置Cookie

Go语言中设置Cookie是通过net/http标准包中的SetCookie函数实现的,它会在responseWriter的头域中添加Set-Cookie头,其值为cookie

http.SetCookie(responseWriter, &cookie)

例如:在HTTP响应中通过设置Set-Cookie头新增Cookie并将其发送给客户端浏览器

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)
        //设置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)
}

查看请求

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响应头Set-Cookie来设置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响应头

Content-Length: 12
Content-Type: text/plain; charset=utf-8
Date: Fri, 22 Jan 2021 19:44:31 GMT
Set-Cookie: account=junchow; HttpOnly
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355

推荐阅读更多精彩内容