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
}
字段描述
ExpiresCookie过期时间,使用绝对时间,比如2020/12/21 00:00:00。
MaxAgeCookie的最大生存秒数时长,使用相对时间,比如300秒。
SecureCookie是否需要安全传输,当为真时表示只有HTTPS才会传输该Cookie。
HttpOnlyCookie是否能够被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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值