Cookie和Session

Cookie和Session

Cookie 和 Session 是 Web 开发绕不开的一个环节,本文介绍 Cookie 和 Session 的原理以及在Go 语言中如何操作

 

1 Cookie

  1. 浏览器发送请求的时候,自动把携带该站点之前存储的Cookie信息。

    2.服务端可以设置Cookie数据。
    3. Cookie是针对单个域名的,不同域名之间的Cookie是独立的。
    4. Cookie数据可以配置过期时间,过期的Cookie数据会被系统清除。

  标准库net/http中定义了Cookie,它代表一个出现在HTTP响应头中Set-Cookie的值里或者HTTP请求头中Cookie的值的HTTP cookie

复制代码
type Cookie struct {
    Name       string
    Value      string
    Path       string
    Domain     string
    Expires    time.Time
    RawExpires string
    // MaxAge=0表示未设置Max-Age属性
    // MaxAge<0表示立刻删除该cookie,等价于"Max-Age: 0"
    // MaxAge>0表示存在Max-Age属性,单位是秒
    MaxAge   int
    Secure   bool
    HttpOnly bool
    Raw      string
    Unparsed []string // 未解析的“属性-值”对的原始文本
}
复制代码

 

2 设置 Cookie

net/http中提供了如下SetCookie函数,它在w的头域中添加Set-Cookie头,该HTTP头的值为cookie。

func SetCookie(w ResponseWriter, cookie *Cookie)

获取 Cookie 的两种方法

// 解析并返回该请求的Cookie头设置的所有cookie
func (r *Request) Cookies() []*Cookie

// 返回请求中名为name的cookie,如果未找到该cookie会返回nil, ErrNoCookie。
func (r *Request) Cookie(name string) (*Cookie, error)

添加Cookie的方法:

// AddCookie向请求中添加一个cookie。
func (r *Request) AddCookie(c *Cookie)

删除 Cookie

cookie := http.Cookie{Name: "testcookiename", Path: "/", MaxAge: -1}
http.SetCookie(w, &cookie)

设置 Cookie

cookie := http.Cookie{Name: "testcookiename", Value: "testcookievalue", Path: "/", MaxAge: 86400}
http.SetCookie(w, &cookie)

 

复制代码
import (
    "fmt"

    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.GET("/cookie", func(c *gin.Context) {
        cookie, err := c.Cookie("gin_cookie") // 获取Cookie
        if err != nil {
            cookie = "NotSet"
            // 设置Cookie
            c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true)
        }
        fmt.Printf("Cookie value: %s \n", cookie)
    })

    router.Run()
}
复制代码

 

"net/http" 操作 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(":80", nil)
}
复制代码

 gin 框架中操作cookie

复制代码
// gin 框架操作 Cookie
// todo 一次性获取所有的Cookie
func main() {
    router := gin.Default()
    // 添加 Cookie
    router.POST("/addCookie", func(context *gin.Context) {
        var cookie string
        var err error
        // 获取 Cookie 没有 cookie err 会出现错误
        if cookie, err = context.Cookie("ljs"); err != nil {
            // 没有 cookie 设置 cookie
            context.SetCookie("ljs", "love hsm", 3600 * 24 , "/", "localhost", false, true)
            context.JSON(http.StatusOK, gin.H{
                "msg" : fmt.Sprintf("添加 cookie 成功"),
            })
            return
        }
        context.JSON(http.StatusOK, gin.H{
            "msg" : fmt.Sprintf("添加 cookie 失败, 原来的 cookie 是 %s", cookie),
        })
        return
    })
    // 删除 Cookie
    router.DELETE("/deleteCookie", func(context *gin.Context) {
        var cookie string
        var err error
        // 获取 Cookie 没有 cookie err 会出现错误
        if cookie, err = context.Cookie("ljs"); err != nil {
            // 没有 cookie, 不用删除
            context.JSON(http.StatusOK, gin.H{
                "msg" : fmt.Sprintf("没有您需要删除的 cookie "),
            })
            return
        }
        context.SetCookie("ljs", "love hsm", -1 , "/", "localhost", false, true)
        context.JSON(http.StatusOK, gin.H{
            "msg" : fmt.Sprintf("删除 cookie 成功, cookie_name = %s, cookie_value = %s", "ljs", cookie),
        })
        return
    })
    
    // 修改 Cookie
    router.PUT("/updateCookie", func(context *gin.Context) {
        // 获取 Cookie
        var err error
        if _, err = context.Cookie("ljs"); err != nil {
            // 没有 cookie
            context.JSON(http.StatusOK, gin.H{
                "msg" : fmt.Sprintf("找不到您需要修改的 cookie_name = %s", "ljs"),
            })
            return
        }
        context.SetCookie("ljs", "love 个屁", 3600 * 12, "/", "localhost", false, true)
        context.JSON(http.StatusOK, gin.H{
            "msg" : fmt.Sprintf("cookie 修改成功 cookie_name= %s, cookie_value = %s", "ljs", "love 个屁"),
        })
        return
    })
    
    // 获取 Cookie
    router.GET("/getCookie", func(context *gin.Context) {
        var cookie string
        var err error
        if cookie, err = context.Cookie("ljs"); err != nil {
            // 没有获取到 cookie
            context.JSON(http.StatusOK, gin.H{
                "msg" : fmt.Sprintf("没有您获取的cookie_name = %s", "ljs"),
            })
            return
        }
        context.JSON(http.StatusOK, gin.H{
            "msg" : fmt.Sprintf("获取的 cookie 是 %s", cookie),
        })
        return
    })
    router.Run()
}
复制代码

 

 

 

 

Session

Session的由来

Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session

问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。

用户登陆成功之后,我们在服务端为每个用户创建一个特定的session和一个唯一的标识,它们一一对应。其中:

  • Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
  • 唯一标识通常称为Session ID会写入用户的Cookie中。

这样该用户后续再次访问时,请求会自动携带Cookie数据(其中包含了Session ID),服务器通过该Session ID就能找到与之对应的Session数据,也就知道来的人是“谁”。

总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在服务端为每个用户保存一个Session数据,该Session数据中能够保存具体的用户数据信息。

另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。

 

posted @   dogRuning  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示