Go --- gin基础知识点(三)

简介: Go --- gin基础知识点

gin 中间件

全局中间件

  • 所有请求都需要经过的中间件
package main
import (
    "fmt"
    "github.com/gin-gonic/gin"
)
// 先定义一个中间件
func MiddleWare() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("中间件开始执行了")
        // 设置变量到Context的key中,可以通过Get()取
        c.Set("request", "中间件")
        status := c.Writer.Status()
        fmt.Println("中间件执行完毕", status)
    }
}
func main() {
    // 1.创建路由
    // 默认使用了2个中间件Logger(), Recovery()
    r := gin.Default()
    // 注册中间件
    r.Use(MiddleWare())
    // {}为代码规范
    {
        r.GET("/test", func(c *gin.Context) {
            // 取值
            req, _ := c.Get("request")
            fmt.Println("request:", req)
            // 页面接收
            c.JSON(200, gin.H{"request": req})
        })
    }
    r.Run(":8000")
}

结果:

Next() 函数


源码:

// Next should be used only inside middleware.
// Next 应该只在中间件中被使用
// It executes the pending handlers in the chain inside the calling handler.
// 挂起现在正在执行的handlers
// See example in GitHub.
func (c *Context) Next() {
    c.index++
    for s := int8(len(c.handlers)); c.index < s; c.index++ {
        c.handlers[c.index](c)
    }
}

测试:

// 中间件中Next的函数的测试
func main() {
  r := gin.New()
  mid1 := func(c *gin.Context) {
    start := time.Now()
    fmt.Println("middleware1 start")
    // 注释 or 不注释,查看输入结果
    //c.Next()
    fmt.Println(time.Since(start))
    fmt.Println("middleware1 ending")
  }
  mid2 := func(c *gin.Context) {
    fmt.Println("middleware2 start")
    c.Next()
    fmt.Println("middleware2 ending")
  }
  r.Use(mid1)
  r.Use(mid2)
  r.GET("/", func(c *gin.Context) {
    c.JSON(http.StatusOK, "hi")
  })
  r.Run(":8000")
}


结果:

# mid1中的Next()执行
middleware1 start
middleware2 start
middleware2 ending
758.6µs
middleware1 ending
# mid1中的Next()注释上
middleware1 start
# 不加Next则不会出现响应时间
0s
middleware1 ending
middleware2 start
middleware2 ending

可以看出,再加Next函数后mid1会先挂起,等其余的中间件(mid2)执行完再继续执行Next函数后的语句,并且这个过程是一个压栈的过程,也就是说先执行的Next后的语句后被执行。

Next之前的操作一般用来做验证处理,访问是否允许之类的。

Next之后的操作一般是用来做总结处理,比如格式化输出、响应结束时间,响应时长计算之类的。

局部中间件

  • 在特殊的路由中指定中间件

示例:

package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
)
func MiddleWare() gin.HandlerFunc {
  return func(c *gin.Context) {
    t := time.Now()
    fmt.Println("中间件开始执行了")
    // 设置变量到Context的key中,可以通过Get()取
    c.Set("request", "中间件")
    // 执行函数
    c.Next()
    // 中间件执行完后续的一些事情
    status := c.Writer.Status()
    fmt.Println("中间件执行完毕", status)
    t2 := time.Since(t)
    fmt.Println("time:", t2)
  }
}
func main() {
  // 1.创建路由
  // 默认使用了2个中间件Logger(), Recovery()
  r := gin.Default()
  //局部中间键使用
  r.GET("/ce", MiddleWare(), func(c *gin.Context) {
    // 取值
    req, _ := c.Get("request")
    fmt.Println("request:", req)
    // 页面接收
    c.JSON(200, gin.H{"request": req})
  })
  r.Run(":8000")
}

结果:

只有在访问"/ce"会执行中间件

会话处理

Cookie

Cookie介绍

  • HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出
  • Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思
  • Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求
  • Cookie由服务器创建,并发送给浏览器,最终由浏览器保存

cookie用途

  • 测试服务端发送cookie给客户端,客户端请求时携带cookie

示例:

package main
import (
  "fmt"
  "github.com/gin-gonic/gin"
)
func main() {
  // 1.创建路由
  // 默认使用了2个中间件Logger(), Recovery()
  r := gin.Default()
  // 服务端要给客户端cookie
  r.GET("cookie", func(c *gin.Context) {
    // 获取客户端是否携带cookie
    cookie, err := c.Cookie("key_cookie")
    if err != nil {
      cookie = "NotSet"
      // 给客户端设置cookie
      //  maxAge int, 单位为秒
      // path,cookie所在目录
      // domain string,域名
      //   secure 是否智能通过https访问
      // httpOnly bool  是否允许别人通过js获取自己的cookie
      c.SetCookie("key_cookie", "value_cookie", 60, "/",
        "localhost", false, true)
    }
    fmt.Printf("cookie的值是: %s\n", cookie)
  })
  r.Run(":8000")
}
// 其中 SetCookie方法的参数的含义为
// maxAge int, 单位为秒
// path,cookie所在目录
// domain string,域名
// secure 是否智能通过https访问
// httpOnly bool  是否允许别人通过js获取自己的cookie
SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)

结果:

cookie的值是: NotSet

这样便有了cookie的值

Cookie缺点

  • 不安全,明文(就像上面的示例的结果)
  • 增加带宽消耗
  • 可以被禁用
  • cookie数量有上限(每个浏览器不同)

Sessions

  • 简单的API:将其用作设置签名(以及可选的加密)cookie的简便方法。
  • 内置的后端可将session存储在cookie或文件系统中。
  • Flash消息:一直持续读取的session值。
  • 切换session持久性(又称“记住我”)和设置其他属性的便捷方法。
  • 旋转身份验证和加密密钥的机制。
  • 每个请求有多个session,即使使用不同的后端也是如此。
  • 自定义session后端的接口和基础结构:可以使用通用API检索并批量保存来自不同商店的session。

示例:

package main
import (
    "fmt"
    "net/http"
    "github.com/gorilla/sessions"
)
// 初始化一个cookie存储对象
// something-very-secret应该是一个你自己的密匙,只要不被别人知道就行
var store = sessions.NewCookieStore([]byte("something-very-secret"))
func main() {
    http.HandleFunc("/save", SaveSession)
    http.HandleFunc("/get", GetSession)
    http.HandleFunc("/del", DelSession)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Println("HTTP server failed,err:", err)
        return
    }
}
func SaveSession(w http.ResponseWriter, r *http.Request) {
    // Get a session. We're ignoring the error resulted from decoding an
    // existing session: Get() always returns a session, even if empty.
    // 获取一个session对象,session-name是session的名字
    session, err := store.Get(r, "session-name")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    // 在session中存储值
    session.Values["foo"] = "bar"
    session.Values[42] = 43
    // 保存更改
    session.Save(r, w)
}
func GetSession(w http.ResponseWriter, r *http.Request) {
    session, err := store.Get(r, "session-name")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    foo := session.Values["foo"]
    fmt.Println(foo)
}
func DelSession(w http.ResponseWriter, r *http.Request) {
  session, err := store.Get(r, "session-name")
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }
  // 将session的时间设为小于零的数就是删除
  session.Options.MaxAge = -1
  // 保存更改
  session.Save(r, w)
}

结果:

# 先save后get,可以取到值
bar
# 然后del再get,就取不到值了
<nil>

参考:

相关文章
|
8天前
|
中间件 Go 数据库
Go开发者必读:Gin框架的实战技巧与最佳实践
在当今快速发展的互联网时代,Web开发的需求日益增长。Go语言以其简洁、高效、并发性强的特点,成为了开发者们的首选。而在Go语言的众多Web框架中,Gin无疑是其中的佼佼者。本文将深入探讨Gin框架的特性、优势以及如何利用Gin构建高性能的Web应用。
|
8天前
|
SQL 安全 前端开发
Go语言Gin框架安全加固:全面解析SQL注入、XSS与CSRF的解决方案
Go语言Gin框架安全加固:全面解析SQL注入、XSS与CSRF的解决方案
|
8天前
|
Java Go 调度
Go语言并发编程原理与实践:面试经验与必备知识点解析
【4月更文挑战第12天】本文分享了Go语言并发编程在面试中的重要性,包括必备知识点和面试经验。核心知识点涵盖Goroutines、Channels、Select、Mutex、Sync包、Context和错误处理。面试策略强调结构化回答、代码示例及实战经历。同时,解析了Goroutine与线程的区别、Channel实现生产者消费者模式、避免死锁的方法以及Context包的作用和应用场景。通过理论与实践的结合,助你成功应对Go并发编程面试。
28 3
|
7月前
|
开发框架 Go 微服务
Golang 语言怎么使用 go-micro 和 gin 开发微服务?
Golang 语言怎么使用 go-micro 和 gin 开发微服务?
144 0
|
8天前
|
关系型数据库 MySQL Go
go语言使用Gin框架链接数据库
go语言使用Gin框架链接数据库
45 0
|
8天前
|
JavaScript 前端开发 NoSQL
go embed 实现gin + vue静态资源嵌入
go embed 实现gin + vue静态资源嵌入
125 0
|
8天前
|
中间件 Go
go 打印gin 中的c.Request的参数
在 Gin 框架中,可以通过 `c.Request` 获取请求对象,从而访问请求的参数。以下是一个示例,展示如何打印出 `c.Request` 中的参数: ```go package main import ( "fmt" "github.com/gin-gonic/gin" ) func LoggerMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // 打印请求方法和路径 fmt.Printf("开始处理请求: %s %s\n", c.Request.Method, c.Request.URL.Pa
101 0
|
6月前
|
前端开发 Java 数据库连接
基于Gin+Gorm框架搭建MVC模式的Go语言企业级后端系统
基于Gin+Gorm框架搭建MVC模式的Go语言企业级后端系统
108 0
|
7月前
|
缓存 前端开发 中间件
Go 框架 Gin 怎么实现允许前端跨域请求?
Go 框架 Gin 怎么实现允许前端跨域请求?
59 0
|
7月前
|
JSON 中间件 Go
Go语言学习 - RPC篇:gin框架的基础能力剖析
gin是非常流行的一款HTTP框架。相较于原生的HTTP server,gin有很多改进点,主要在于3点: 1. 上手简单,开发思路与原生HTTP基本一致 2. 引入多个工具库,提高了开发效率 3. 生态丰富,有许多开源的组件 围绕着gin框架,我们将展开今天的话题。
117 2
Go语言学习 - RPC篇:gin框架的基础能力剖析