快捷搜索:  汽车  科技

go语言给浏览器设置cookie(Go语言Web)

go语言给浏览器设置cookie(Go语言Web)cookie:=http.Cookie{ Name:"_cookie" Value:session.Uuid HttpOnly:true Path:"/" } http.SetCookie(writer &cookie) http.Redirect(writer request "/" 302) 上述代码是在用户认证通过后将 Session ID 通过 Cookie 存储到客户端,以便后续记住用户登录状态,直到用户关闭浏览器(没有设置过期时间)。通过这段代码,可以看出要在响应中发送 Cookie,需要先通过 http.Cookie 初始化一个 Cookie 对象,再通过 http.SetCookie 方法将这个 Cookie 写入到 HTTP 响应中,这样发送响应给客户端的时候就会带上这个 Cookie 了。了解了 Cookie 的基

1、Cookie 简介

介绍完了 Go 语言的 HTTP 请求和响应处理,接下来,我们来看看 Go 语言中 Cookie 技术的实现,由于 HTTP 协议本身是无状态的,所以引入了 Cookie 来实现客户端用户识别和状态管理,关于 Cookie 本身这里不多做介绍,你可以在维基百科或者阅读 HTTP 报文首部字段(五):扩展字段篇(Cookie)这篇教程了解更多细节。

我们可以在 HTTP 响应头中通过 Set-Cookie 字段设置 Cookie,然后在下次请求时就会在请求头 Cookie 中自动包含新增的 Cookie。你可以在 Chrome 浏览器的控制台中通过 Application->Storage->Cookies 查看指定域名下的所有 Cookie:

go语言给浏览器设置cookie(Go语言Web)(1)

可以在 Cookie 列表顶部抬头看到 Cookie 的所有属性。

2、Cookie 结构体

Go 专门提供了一个 http.Cookie 结构体来表示 Cookie,其中的字段对应着 Cookie 的所有属性:

//ACookierepresentsanHTTPcookieassentintheSet-CookieHeaderofan //HTTPresponseortheCookieheaderofanHTTPRequest. // //Seehttps://tools.ietf.org/html/rfc6265fordetails. typeCookiestruct{ Namestring Valuestring Pathstring//optional Domainstring//optional Expirestime.Time//optional RawExpiresstring//forreadingcookiesonly //MaxAge=0meansno'Max-Age'attributespecified. //MaxAge<0meansdeletecookienow equivalently'Max-Age:0' //MaxAge>0meansMax-Ageattributepresentandgiveninseconds MaxAgeint Securebool HttpOnlybool SameSiteSameSite Rawstring Unparsed[]string//Rawtextofunparsedattribute-valuepairs }

我们可以将其与上面截图中的 Cookie 属性一一对应,如果你了解 Cookie 的基本结构的话,很容易知道每个字段的含义。如果你不了解的话,可以通过点击上面 Cookie 简介中给出的链接去了解。

这里,我们重点介绍下 Expires 字段:

  • 如果 Expires 字段为空,则 Cookie 就是 Session Cookie 或者叫临时 Cookie,这个 Cookie 会随着浏览器的关闭而销毁。
  • 如果设置了 Expires,那么这个 Cookie 就是持久 Cookie,直到过期时间后才会销毁。

有两种方法来设置过期时间:一种是直接设置 Expires 字段,一种是设置 MaxAge 字段。前者表示到期的具体时间点,后者表示 Cookie 的有效时长(单位是秒)。这并不是 Go 语言的设计,而是不同浏览器的混乱标准使然,比如虽然 HTTP/1.1 有意废弃 Expires,不过 IE 6、7、8 却不支持 MaxAge 字段。通常,考虑到默认时区问题,本地时间不可靠,推荐通过 MaxAge 字段设置 Cookie 过期时间,不过对于 Web 应用而言,通常不设置过期时间,让 Cookie 随着浏览器关闭而失效即可。

3、发送 Cookie 到客户端

了解了 Cookie 的基本结构,以及如何在 Go 语言中表示后,我们尝试在 HTTP 响应中通过设置 Set-Cookie 头新增 Cookie 并将其发送给客户端浏览器,在此之前的在线论坛项目中,已经在用户认证时用到了 Cookie 设置:

cookie:=http.Cookie{ Name:"_cookie" Value:session.Uuid HttpOnly:true Path:"/" } http.SetCookie(writer &cookie) http.Redirect(writer request "/" 302)

上述代码是在用户认证通过后将 Session ID 通过 Cookie 存储到客户端,以便后续记住用户登录状态,直到用户关闭浏览器(没有设置过期时间)。通过这段代码,可以看出要在响应中发送 Cookie,需要先通过 http.Cookie 初始化一个 Cookie 对象,再通过 http.SetCookie 方法将这个 Cookie 写入到 HTTP 响应中,这样发送响应给客户端的时候就会带上这个 Cookie 了。

接下来,我们在 goblog 项目中演示发送 Cookie 到客户端,这一次,我们不通过写入 Cookie 到 HTTP 响应,而是直接通过 HTTP 响应头 Set-Cookie 来设置 Cookie,在 goblog/handlers/common.go 中新增 SetCookie 处理器:

funcSetCookie(whttp.ResponseWriter r*http.Request){ c1:=http.Cookie{ Name:"username" Value:url.QueryEscape("学院君") HttpOnly:true } c2:=http.Cookie{ Name:"website" Value:"https://xueyuanjun.com" HttpOnly:true } w.Header().Add("Set-Cookie" c1.String()) w.Header().Add("Set-Cookie" c2.String()) fmt.Fprintln(w "通过HTTP响应头发送Cookie信息") }

这里我们新增了两个 Cookie,所以使用了 w.Header().Add 方法,如果用 Set 方法,后面的 Set-Cookie 头会覆盖前面的,另外,由于 Cookie 值包含了中文字符,需要通过 url.QueryEscape 方法进行 URL 编码,否则无法正常显示。

在 routes/web.go 中注册对应的路由:

WebRoute{ "SetCookie" "GET" "/setcookies" handlers.SetCookie }

重启 HTTP 服务器,在浏览器中访问 http://localhost:8080/setcookies,就可以在响应结果中看到对应的 Cookie 信息了:

go语言给浏览器设置cookie(Go语言Web)(2)

当然也可以通过 http.SetCookie 方法写入 Cookie 到 HTTP 响应来实现,对应的代码如下,这样做更便捷:

http.SetCookie(w &c1) http.SetCookie(w &c2)

设置 Cookie 有效期

还可以通过 Expires/MaxAge 设置 Cookie 的有效期:

c1:=http.Cookie{ Name:"username" ... Expires:time.Now().AddDate(0 0 1) //Cookie有效期设置为1天 } c2:=http.Cookie{ Name:"website" ... MaxAge:1000 //Cookie有效期设置为1000s }

这样,就可以在响应中看到对应的 Cookie 有效期了:

go语言给浏览器设置cookie(Go语言Web)(3)

4、从请求中读取 Cookie

一旦通过 Set-Cookie 响应头将 Cookie 信息发送到客户端浏览器,那么在 Cookie 有效期内,下次同域名下的用户请求将自动在请求头中包含对应的 Cookie 信息,比如我们访问 http://localhost:8080,就可以在请求头 Cookie 中看到上次响应返回的 Cookie:

go语言给浏览器设置cookie(Go语言Web)(4)

要在服务端获取这些 Cookie 信息,可以通过读取请求头的方式:

cookie:=r.Header.Get("Cookie")

但是这种方式读取的 Cookie 字符串值还需要进行解析,才能得到每个 Cookie 的值,为此可以通过更加便捷的专门用于读取每个 Cookie 的 r.Cookie 方法(r 表示 HTTP 请求对象实例),我们在 handlers/common.go 中新增一个 GetCookie 方法:

funcGetCookie(whttp.ResponseWriter r*http.Request){ c1 err:=r.Cookie("username") iferr!=nil{ fmt.Fprintln(w "名为username的Cookie不存在") return } username _:=url.QueryUnescape(c1.Value) c2 err:=r.Cookie("website") iferr!=nil{ fmt.Fprintln(w "名为website的Cookie不存在") return } website:=c2.Value fmt.Fprintf(w "从用户请求中读取的Cookie:{username:%s website:%s}\n" username website) }

需要注意的是 r.Cookie 方法返回的是指针类型的 Cookie 对象和一个错误信息,需要通过调用 Cookie 对象上的 Value 属性返回对应的 Cookie 值,对于 username 而言,还需要通过 url.QueryUnescape 对编码值进行解码。

在 routes/web.go 中注册一个对应的路由:

WebRoute{ "GetCookie" "GET" "/getcookies" handlers.GetCookie }

然后重启 HTTP 服务器,在浏览器中访问 http://localhost:8080/getcookies,website Cookie 如果已经过期,则会打印错误消息:

go语言给浏览器设置cookie(Go语言Web)(5)

重新访问 http://localhost:8080/setcookies,再访问 http://localhost:8080/getcookies,就可以成功获取并打印出所有的 Cookie 信息:

go语言给浏览器设置cookie(Go语言Web)(6)

如果想要一次性获取所有 Cookie,还可以通过 r.Cookies() 方法,该方法会返回的是 Cookie 对象指针类型切片:

cookies:=r.Cookies() c1:=cookies[0]//username=学院君 c2:=cookies[1]//website=https://xueyuanjun.com

5、删除 Cookie

如果想要在 Cookie 过期之前提前删除 Cookie,可以将 MaxAge 设置为小于 0 的值即可:

c2:=http.Cookie{ Name:"website" Value:"https://xueyuanjun.com" HttpOnly:true MaxAge:-1 //Cookie有效期设置为-1,就会在当前响应发送给客户端后销毁该Cookie }

如果用 Expires 字段来设置的话,可以设置 Unix 时间戳的值为 1(对应的绝对时间是 1970-01-01 08:00:01 0800 CST,也就是一个过去的时间):

c2:=http.Cookie{ Name:"website" Value:"https://xueyuanjun.com" HttpOnly:true Expires:time.Unix(1 0) //Cookie有效期设置为过去的时间 }

使用 Cookie 设置一次性消息

所谓一次性消息,指的是页面重新加载后消息就不存在了,也就是该消息只能被读取一次,不管你用不用它都不复存在了。我们可以结合上面的删除 Cookie 功能来实现这个一次性消息功能,首先在 common.go 中新增一个 SetWelcomeMessage 处理器:

funcSetWelcomeMessage(whttp.ResponseWriter r*http.Request){ msg:="欢迎访问学院君网站" cookie:=http.Cookie{ Name:"welcome_message" Value:base64.URLEncoding.EncodeToString([]byte(msg)) } http.SetCookie(w &cookie) http.Redirect(w r "/get_welcome_message" 302) }

这里发送 Cookie 到客户端和前面的新增 Cookie 逻辑完全一样,最后通过 http.Redirect 将请求重定向到 /get_welcome_message 路由,另外这一次我们通过 Base64 对 Cookie 值进行编码,因为其中包含中文和特殊字符。接下来我们继续在 common.go 中编写 /get_welcome_message 路由对应的处理器 GetWelcomeMessage:

funcGetWelcomeMessage(whttp.ResponseWriter r*http.Request){ cookie err:=r.Cookie("welcome_message") iferr!=nil{ fmt.Fprintln(w "没有在Cookie中找到欢迎消息") }else{ delCookie:=http.Cookie{ Name:"welcome_message" MaxAge:-1 } http.SetCookie(w &delCookie) msg _:=base64.URLEncoding.DecodeString(cookie.Value) fmt.Fprintln(w string(msg)) } }

在这段代码中,首先通过 r.Cookie 方法从 Cookie 中读取欢迎消息,读取之后,通过 Base64 对其进行解码,然后作为响应实体返回给客户端,这一块和之前读取 Cookie 逻辑一样,只是新增了读取成功之后,删除这个 Cookie 的功能。

最后,在 routes/web.go 中注册上述处理器方法对应的路由:

WebRoute{ "SetMessage" "GET" "/set_welcome_message" handlers.SetWelcomeMessage } WebRoute{ "GetMessage" "GET" "/get_welcome_message" handlers.GetWelcomeMessage }

重启 HTTP 服务器,在浏览器中访问 http://localhost:8080/set_welcome_message,页面会重定向到 http://localhost:8080/get_welcome_message,然后打印出欢迎消息,说明 Cookie 读取成功:

go语言给浏览器设置cookie(Go语言Web)(7)

如果查看 Chrome 控制台的话,可以在 Network 标签页看到对应的 Cookie 响应头和请求头:

go语言给浏览器设置cookie(Go语言Web)(8)

在 get_welcome_message 请求头中可以看到对应的 Cookie,此外这个请求的响应头还包含了删除 Cookie 的逻辑:

go语言给浏览器设置cookie(Go语言Web)(9)

如果在「Application」标签页查看 Cookie 的话,会发现已经没有 welcome_message 了(website 到了过期时间自动销毁,所以也看不到了):

go语言给浏览器设置cookie(Go语言Web)(10)

好了,关于 HTTP Cookie 功能我们简单介绍到这里,下篇教程,我们来探讨在 Go 语言中如何基于 Cookie 实现 Session 技术。

(全文完)

猜您喜欢: