脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Go语言读取,设置Cookie及设置cookie过期方法详解

Go语言读取,设置Cookie及设置cookie过期方法详解

2022-09-24 14:15骏马金龙 Golang

这篇文章主要介绍了Go语言读取,设置Cookie及设置cookie过期方法详解,需要的朋友可以参考下

Cookie用来解决http协议无状态的问题。

首先,在服务端生成Cookie,然后在http响应header中设置Set-Cookie字段,客户端会读取到Set-Cookie字段后,会将cookie信息存储起来,下次继续访问服务端时,会在http请求中设置Cookie字段并发送给服务端,服务端可以解析这个Cookie字段,从而知道这个客户端之前已经和自己有过会话(上下文),然后再执行相应的逻辑代码。

Cookie分为两种类型:session cookie和persistent cookie。

  • Session Cookie也称为临时Cookie,客户端只会将cookie数据存储在http client进程的内容中,不会保存到磁盘文件中(或其它存储设备),浏览器关闭(或者说http client进程退出)的时候,cookie就删除了
  • persistent cookie是持久化cookie,浏览器退出也不删除,而是根据服务端发送cookie时设置的过期时长判断cookie是否过期,只要cookie还有效,客户端就会携带cookie访问服务端

Cookie struct

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ 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

一个Cookie代表一个http cookie。服务端可以设置多个Set-Cookie字段发送给客户端。

Name和Value分别设置这个cookie的key/value。一定要有至少一个能唯一区分客户端的ID类的value。

Expires指定cookie到什么时候过期,是一个时间值。当指定为过去的时间值时,表示这个cookie已经过期。

MaxAge也用来设置cookie什么时候过期,MaxAge为负数或等于0表示立即过期,MaxAge大于0表示过多少秒之后过期。

MaxAge和Expires都可以设置cookie持久化时的过期时长,Expires是老式的过期方法,如果可以,应该使用MaxAge设置过期时间,但有些老版本的浏览器不支持MaxAge。如果要支持所有浏览器,要么使用Expires,要么同时使用MaxAge和Expires。

Path和Domain设置访问哪些路径或域名范围的主机时应该携带这个cookie。如果不设置,则访问所有路径、该Domain下的主机都携带cookie。

?
1
2
3
4
5
6
cookie.Path("/WEB16");
    代表访问WEB16应用中的任何资源都携带cookie
cookie.Path("/WEB16/cookietest");
    代表访问WEB16中的cookietest时才携带cookie信息
cookie.Domain(".foo.com");
    这对foo.com域下的所有主机都生效(如www.foo.com),但不包括子域www.abc.foo.com

Secure和HttpOnly字段为cookie提供一些保护机制。这两个cookie属性的介绍,参见:

  • Cookie Secure
  • Cookie HttpOnly

Cookie有一个String()方法,用来将Cookie实例转换成字符串。转化成字符串之后就可以直接设置在Header中。

例如,下面是登录youtube的时候,对方发送给我的cookie:

Go语言读取,设置Cookie及设置cookie过期方法详解

设置Cookie并发送给客户端

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main
 
import (
    "fmt"
    "net/http"
)
 
func setCookie(w http.ResponseWriter, r *http.Request) {
    // 定义两个cookie
    c1 := http.Cookie{
        Name:  "first_cookie",
        Value: "Go Programming",
    }
    c2 := http.Cookie{
        Name:     "second_cookie",
        Value:    "Go Web Programming",
        HttpOnly: true,
    }
    // 设置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()
}

访问http://127.0.0.1:8080/set_cookie时,查看Header将显式Set-Cookie字段。

?
1
2
3
4
5
6
7
8
9
10
$ 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包提供了一个SetCookie()函数,可以直接用来设置Set-Cookie字段。

?
1
func SetCookie(w ResponseWriter, cookie *Cookie)

注意,第二个字段是指针类型的Cookie

修改前面的示例,使用SetCookie()函数发送Set-Cookie字段:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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

由于客户端发起请求时,如果携带cookie,是直接放在Request的Cookie Header中的。所以,可以通过Request取得客户端携带的cookie信息。当然,也可以通过Request的方法Cookie()或Cookies()取得cookie信息。

?
1
2
func (r *Request) Cookie(name string) (*Cookie, error)
func (r *Request) Cookies() []*Cookie
  • Cookie(Name)只取某个cookie
  • Cookies()取所有的cookie

下面是通过Request Header的方式取Cookie的示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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()
}

在访问http://127.0.0.1:8080/set_cookie之后不要关闭浏览器,再次访问http://127.0.0.1:8080/get_cookie,将输出:

?
1
first_cookie="Go Programming"; second_cookie="Go Web Programming"

或者,使用curl记录cookie,并下次访问时读取cookie:

?
1
2
3
$ 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:

?
1
2
3
4
5
6
7
8
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)
}

访问结果:

?
1
2
3
4
$ 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"]

设置cookie过期示例:发送临时消息

有时候可能想要让客户端的某些操作只显示一次相关消息,例如post一篇帖子失败后,应该显示失败信息,但下次再访问不应该再显示这些失败信息。

通过设置cookie过期的技巧,可以实现一些一次性操作。设置cookie过期的方式是设置MaxAge为负数或0,为了兼容所有浏览器,可以设置Expires为过去的一段时间。

下面的示例中,将一段数据使用URL格式编码后作为flash cookie的值。当客户端访问set_message的时候,就会在http Client进程中保存这段cookie。再访问show_message的时候,handler解析客户端携带的cookie,并设置一个Set-Cookie字段,这个字段的作用是使之前保存的cookie过期。然后输出解码后客户端携带的cookie的值。再次刷新show_message,将得到不同的输出结果。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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测试。注意,首先访问set_message的时候,保存cookie到b.cookie文件。再访问show_message的时候,也要带上-c b.cookie将已保存的cookie设置为过期,之后再访问show_message就会出现预期的结果:

?
1
2
3
4
5
6
$ 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

原文链接:https://www.cnblogs.com/f-ck-need-u/p/10035803.html

延伸 · 阅读

精彩推荐
  • GolangGolang之casbin权限管理的实现

    Golang之casbin权限管理的实现

    这篇文章主要介绍了Golang之casbin权限管理的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    HaimaBlog11532021-01-30
  • GolangGo语言七篇入门教程五文件及包

    Go语言七篇入门教程五文件及包

    本章节主要介绍go语言的文件处理与包管理,本文是Go语言七篇入门教程系列篇,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步...

    小生凡一8912021-12-01
  • GolangGo语言中slice的用法实例分析

    Go语言中slice的用法实例分析

    这篇文章主要介绍了Go语言中slice的用法,实例分析了slice的功能及使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    不是JS1892020-04-17
  • Golanggo语言中linkname的用法

    go语言中linkname的用法

    这篇文章主要介绍了go语言中linkname的用法,本文给点俺家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 ...

    暮雨6792020-05-27
  • Golanggolang读取文件的常用方法总结

    golang读取文件的常用方法总结

    今天小编就为大家分享一篇关于golang读取文件的常用方法总结,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编...

    思维的深度2732020-05-24
  • Golanggo语言中切片Slice与数组Array对比以及panic: runtime error: index out of range问题解决

    go语言中切片Slice与数组Array对比以及panic: runtime error: index out o

    go语言中数组与其他语言有在显著的不同,包括其不能够进行添加,以及值拷贝的特性,下面这篇文章主要给大家介绍了关于go语言中切片Slice与数组Array对比以...

    大锤爱编程10592022-07-20
  • Golang从源码的角度看Go语言Flag库如何解析命令行参数!

    从源码的角度看Go语言Flag库如何解析命令行参数!

    Parse的代码里用到了一个,CommandLine共享变量,这就是内部库维护的FlagSet,所有的参数都会插到里面的变量地址向地址的指向赋值绑定。...

    机智的程序员小熊10662021-08-11
  • Golang如何在 ubuntu linux 上配置 go 语言的 qt 开发环境

    如何在 ubuntu linux 上配置 go 语言的 qt 开发环境

    这篇文章主要介绍了如何在 ubuntu linux 上配置 go 语言的 qt 开发环境,本文分步骤通过实例代码相结合给大家介绍的非常详细,对大家的学习或工作具有一定...

    fuhuizn4892020-06-09