# Cookie

## HTTP协议

在http协议的请求头（Request Header）（参考1）中，有一个`Cookie`字段。可以在http请求中加入相应的cookie信息。

在http协议的响应头（Response Header）中，有一个`Set-Cookie`字段，通过该字段客户端可以保存服务端返回的cookie信息，以便在下次请求的时候携带上cookie

## Go语言Cookie结构体

在go语言中的`net/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
}
```

解释一下上面的`MaxAge`字段，`MaxAge`字段为一个整型：

* 当大于0时，表示该cookie可以被保存多长时间（以秒为单位），此时浏览器一般会把它保存在本地文件中，浏览器退出后重新登录，此cookie依旧可用；
* 当MaxAge为0时，该cookie会被浏览器保存在内存中，浏览器没有退出的话，一直可以使用该cookie，但退出后就会不能被使用；
* 当MaxAge小于0时，表示服务器告诉浏览器立即删除该cookie。

## 示例

下面以一个go程序（参考2）来模拟cookie：

* 当访问`/readcookie`路径时，服务器在http协议的`response body`中返回浏览器携带的cookie信息；如果浏览器未携带cookie，则返回提示信息
* 当访问`/writecookie`路径时，服务器在http的`response header`中的`Set-Cookie`字段返回一个cookie，该cookie在浏览器再次访问`/readcookie`路径时将被使用
* 当访问`/deletecookie`路径时，服务器将cookie的MaxAge字段设为-1，告诉浏览器立即删除该cookie

服务器代码如下：

```
package main

import (
    "net/http"
)

func SayHello(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello"))
}

func ReadCookieServer(w http.ResponseWriter, req *http.Request) {
    // read cookie
    cookie, err := req.Cookie("testcookiename")
    if err == nil {
        cookievalue := cookie.Value
        w.Write([]byte("<b>cookie的值是：" + cookievalue + "</b>\n"))
    } else {
        w.Write([]byte("<b>读取出现错误：" + err.Error() + "</b>\n"))
    }
}

func WriteCookieServer(w http.ResponseWriter, req *http.Request) {
    cookie := http.Cookie{Name: "testcookiename", Value: "testcookievalue", Path: "/", MaxAge: 86400}
    http.SetCookie(w, &cookie)

    w.Write([]byte("<b>设置cookie成功。</b>\n"))
}

func DeleteCookieServer(w http.ResponseWriter, req *http.Request) {
    cookie := http.Cookie{Name: "testcookiename", Path: "/", MaxAge: -1}
    http.SetCookie(w, &cookie)

    w.Write([]byte("<b>删除cookie成功。</b>\n"))
}

func main() {
    http.HandleFunc("/", SayHello)
    http.HandleFunc("/readcookie", ReadCookieServer)
    http.HandleFunc("/writecookie", WriteCookieServer)
    http.HandleFunc("/deletecookie", DeleteCookieServer)

    http.ListenAndServe(":8082", nil)
}
```

接下来我们第一次访问 `x.x.x.x:8082/readcookie`，如下没有任何cookie信息

![](https://877178945-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxQp7jad-qy7_GuU%2Fsync%2Fbecccfbfd27e11768cd3903ea18eede389b0fb36.png?generation=1588235886511938\&alt=media)

然后我们访问`x.x.x.x:8082/writecookie`

![](https://877178945-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxQp7jad-qy7_GuU%2Fsync%2F922258fc9d832eecffaba2af6f2619c31bf7940e.png?generation=1588235887182197\&alt=media)

然后，我们再访问`x.x.x.x:8082/readcookie`，此时我们发现这一次浏览器携带保存的cookie

![](https://877178945-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxQp7jad-qy7_GuU%2Fsync%2Ff5bc5d2312498a23766a7856445cd2fa50c68c64.png?generation=1588235886182190\&alt=media)

我们可以查看当前请求所携带的cookie信息（右击firefox的导航栏 --》 菜单栏 --》 工具 --》 页面信息 --》 安全 --》 cookie）

![](https://877178945-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxQp7jad-qy7_GuU%2Fsync%2F34a325684cfb345c52e5b371b5c710c94d7b0b3f.png?generation=1588235886800812\&alt=media)

关闭浏览器，再次访问`x.x.x.x:8082/readcookie`，还是能看到cookie信息，说明浏览器把它保存在本地文件中了

![](https://877178945-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxQp7jad-qy7_GuU%2Fsync%2Ff5bc5d2312498a23766a7856445cd2fa50c68c64.png?generation=1588235886182190\&alt=media)

接下来，我们访问`x.x.x.x:8082/deletecookie`

![](https://877178945-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxQp7jad-qy7_GuU%2Fsync%2Fd14769d8e7c9eb356bfdee9d8a7617f93da4ac24.png?generation=1588235887446983\&alt=media)

然后，再访问`x.x.x.x:8082/readcookie`，发现cookie已经被浏览器删掉了，所以本次请求没有cookie信息

![](https://877178945-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M69DxQp7jad-qy7_GuU%2Fsync%2Fbecccfbfd27e11768cd3903ea18eede389b0fb36.png?generation=1588235886511938\&alt=media)

## 参考

（1）[https://zh.wikipedia.org/wiki/HTTP%E5%A4%B4%E5%AD%97%E6%AE%B5](https://zh.wikipedia.org/wiki/HTTP%E5%A4%B4%E5%AD%97%E6%AE%B5)

（2）[https://studygolang.com/articles/5905](https://studygolang.com/articles/5905)
