go 语言框架 gin 的中文文档

时间:2025-02-25 16:48:58

安装与配置

安装:

$ go get /gin-gonic/gin.v1

注意:确保 GOPATH GOROOT 已经配置

导入:

import "/gin-gonic/gin.v1"

框架架构

  • HTTP 服务器

1.默认服务器

()

服务器

除了默认服务器中 () 的方式外,还可以用 (),比如

func main() {
	router := gin.Default()
	http.ListenAndServe(":8080", router)
}

或者自定义 HTTP 服务器的配置:

func main() {
	router := gin.Default()

	s := &http.Server{
		Addr:           ":8080",
		Handler:        router,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	s.ListenAndServe()
}

服务器替换方案 想无缝重启、停机吗? 以下有几种方式:

我们可以使用 fvbock/endless 来替换默认的 ListenAndServe。但是 windows 不能使用。

router := gin.Default()
router.GET("/", handler)
// [...]
endless.ListenAndServe(":4242", router)

除了 endless 还可以用manners:

manners 兼容windows

(":8888", r)

  • 生命周期

  • Context

路由

  • 基本路由 gin 框架中采用的路由库是 httprouter。
	// 创建带有默认中间件的路由:
	// 日志与恢复中间件
	router := gin.Default()
	//创建不带中间件的路由:
	//r := ()

	router.GET("/someGet", getting)
	router.POST("/somePost", posting)
	router.PUT("/somePut", putting)
	router.DELETE("/someDelete", deleting)
	router.PATCH("/somePatch", patching)
	router.HEAD("/someHead", head)
	router.OPTIONS("/someOptions", options)

  • 路由参数

api 参数通过Context的Param方法来获取

("/string/:name", func(c *) {
    	name := ("name")
    	("Hello %s", name)
    })

URL 参数通过 DefaultQuery 或 Query 方法获取

// url 为 http://localhost:8080/welcome?name=ningskyer时
// 输出 Hello ningskyer
// url 为 http://localhost:8080/welcome时
// 输出 Hello Guest
("/welcome", func(c *) {
	name := ("name", "Guest") //可设置默认值
	// 是 ().Get("lastname") 的简写
	lastname := ("lastname") 
	("Hello %s", name)
})

表单参数通过 PostForm 方法获取

//form
("/form", func(c *) {
	type := ("type", "alert")//可设置默认值
	msg := ("msg")
	title := ("title")
	("type is %s, msg is %s, title is %s", type, msg, title)
})

  • 路由群组
	someGroup := router.Group("/someGroup")
    {
        someGroup.GET("/someGet", getting)
		someGroup.POST("/somePost", posting)
	}

控制器

  • 数据解析绑定

模型绑定可以将请求体绑定给一个类型,目前支持绑定的类型有 JSON, XML 和标准表单数据 (foo=bar&boo=baz)。 要注意的是绑定时需要给字段设置绑定类型的标签。比如绑定 JSON 数据时,设置 json:"fieldname"。 使用绑定方法时,Gin 会根据请求头中 Content-Type 来自动判断需要解析的类型。如果你明确绑定的类型,你可以不用自动推断,而用 BindWith 方法。 你也可以指定某字段是必需的。如果一个字段被 binding:"required" 修饰而值却是空的,请求会失败并返回错误。

// Binding from JSON
type Login struct {
	User     string `form:"user" json:"user" binding:"required"`
	Password string `form:"password" json:"password" binding:"required"`
}

func main() {
	router := gin.Default()

	// 绑定JSON的例子 ({"user": "manu", "password": "123"})
	router.POST("/loginJSON", func(c *gin.Context) {
		var json Login

		if c.BindJSON(&json) == nil {
			if json.User == "manu" && json.Password == "123" {
				c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
			} else {
				c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			}
		}
	})

	// 绑定普通表单的例子 (user=manu&password=123)
	router.POST("/loginForm", func(c *gin.Context) {
		var form Login
		// 根据请求头中 content-type 自动推断.
		if c.Bind(&form) == nil {
			if form.User == "manu" && form.Password == "123" {
				c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
			} else {
				c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
			}
		}
	})
	// 绑定多媒体表单的例子 (user=manu&password=123)
	router.POST("/login", func(c *gin.Context) {
		var form LoginForm
		// 你可以显式声明来绑定多媒体表单:
		// (&form, )
		// 或者使用自动推断:
		if c.Bind(&form) == nil {
			if form.User == "user" && form.Password == "password" {
				c.JSON(200, gin.H{"status": "you are logged in"})
			} else {
				c.JSON(401, gin.H{"status": "unauthorized"})
			}
		}
	})
	// Listen and serve on 0.0.0.0:8080
	router.Run(":8080")
}

请求

  • 请求头

  • 请求参数

  • Cookies

  • 上传文件
("/upload", func(c *) {

    file, header , err := ("upload")
    filename := 
    ()
    out, err := ("./tmp/"+filename+".png")
    if err != nil {
        (err)
    }
    defer ()
    _, err = (out, file)
    if err != nil {
        (err)
    }   
})

响应

  • 响应头

  • 附加Cookie

  • 字符串响应
(, "some string")

  • JSON/XML/YAML响应
("/moreJSON", func(c *) {
	// You also can use a struct
	var msg struct {
		Name    string `json:"user" xml:"user"`
		Message string
		Number  int
	}
	 = "Lena"
	 = "hey"
	 = 123
	// 注意  变成了 "user" 字段
	// 以下方式都会输出 :   {"user": "Lena", "Message": "hey", "Number": 123}
	(, {"user": "Lena", "Message": "hey", "Number": 123})
	(, {"user": "Lena", "Message": "hey", "Number": 123})
	(, {"user": "Lena", "Message": "hey", "Number": 123})
	(, msg)
	(, msg)
	(, msg)
})
		

  • 视图响应

先要使用 LoadHTMLTemplates() 方法来加载模板文件

func main() {
	router := gin.Default()
	//加载模板
	router.LoadHTMLGlob("templates/*")
	//("templates/", "templates/")
	//定义路由
	router.GET("/index", func(c *gin.Context) {
		//根据完整文件名渲染模板,并传递参数
		c.HTML(http.StatusOK, "", gin.H{
			"title": "Main website",
		})
	})
	router.Run(":8080")
}

模板结构定义

<html>
	<h1>
		{{ .title }}
	</h1>
</html>

不同文件夹下模板名字可以相同,此时需要 LoadHTMLGlob() 加载两层模板路径

router.LoadHTMLGlob("templates/**/*")
router.GET("/posts/index", func(c *gin.Context) {
	c.HTML(http.StatusOK, "posts/", gin.H{
		"title": "Posts",
	})
	c.HTML(http.StatusOK, "users/", gin.H{
		"title": "Users",
	})
	
}

templates/posts/

<!-- 注意开头 define 与结尾 end 不可少 -->
{{ define "posts/" }}
<html><h1>
	{{ .title }}
</h1>
</html>
{{ end }}

gin也可以使用自定义的模板引擎,如下

```go
import "html/template"

func main() {
	router := ()
	html := (("file1", "file2"))
	(html)
	(":8080")
}

  • 文件响应
//获取当前文件的相对路径
("/assets", "./assets")
//
("/more_static", ("my_file_system"))
//获取相对路径下的文件
("/", "./resources/")

  • 重定向
("/redirect", func(c *) {
	//支持内部和外部的重定向
    (, "/")
})

  • 同步异步

goroutine 机制可以方便地实现异步处理

func main() {
	r := gin.Default()
	//1. 异步
	r.GET("/long_async", func(c *gin.Context) {
		// goroutine 中只能使用只读的上下文 ()
		cCp := c.Copy()
		go func() {
			time.Sleep(5 * time.Second)

			// 注意使用只读上下文
			log.Println("Done! in path " + cCp.Request.URL.Path)
		}()
	})
	//2. 同步
	r.GET("/long_sync", func(c *gin.Context) {
		time.Sleep(5 * time.Second)

		// 注意可以使用原始上下文
		log.Println("Done! in path " + c.Request.URL.Path)
	})

	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

视图

  • 传参

  • 视图组件

中间件

  • 分类使用方式
// 1.全局中间件
(())
(())

// 2.单路由的中间件,可以加任意多个
("/benchmark", MyMiddelware(), benchEndpoint)

// 3.群组路由的中间件
authorized := ("/", MyMiddelware())
// 或者这样用:
authorized := ("/")
(MyMiddelware())
{
	("/login", loginEndpoint)
}

  • 自定义中间件
//定义
func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()

		// 在gin上下文中定义变量
		c.Set("example", "12345")

		// 请求前

		c.Next()//处理请求

		// 请求后
		latency := time.Since(t)
		log.Print(latency)

		// access the status we are sending
		status := c.Writer.Status()
		log.Println(status)
	}
}
//使用
func main() {
	r := gin.New()
	r.Use(Logger())

	r.GET("/test", func(c *gin.Context) {
		//获取gin上下文中的变量
		example := c.MustGet("example").(string)

		// 会打印: "12345"
		log.Println(example)
	})

	// 监听运行于 0.0.0.0:8080
	r.Run(":8080")
}

  • 中间件参数

  • 内置中间件 1.简单认证BasicAuth

// 模拟私有数据
var secrets = gin.H{
	"foo":    gin.H{"email": "foo@", "phone": "123433"},
	"austin": gin.H{"email": "austin@", "phone": "666"},
	"lena":   gin.H{"email": "lena@", "phone": "523443"},
}

func main() {
	r := gin.Default()

	// 使用  中间件,设置授权用户
	authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{
		"foo":    "bar",
		"austin": "1234",
		"lena":   "hello2",
		"manu":   "4321",
	}))

	// 定义路由
	authorized.GET("/secrets", func(c *gin.Context) {
		// 获取提交的用户名(AuthUserKey)
		user := c.MustGet(gin.AuthUserKey).(string)
		if secret, ok := secrets[user]; ok {
			c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
		} else {
			c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})
		}
	})

	// Listen and serve on 0.0.0.0:8080
	r.Run(":8080")
}

数据库

  • Mongodb

Golang常用的Mongodb驱动为 mgo.v2, 查看文档

mgo 使用方式如下:

//定义 Person 结构,字段须为首字母大写
type Person struct {
	Name string
	Phone string
}

("/mongo", func(context *){
	//可本地可远程,不指定协议时默认为http协议访问,此时需要设置 mongodb 的nohttpinterface=false来打开httpinterface。
	//也可以指定mongodb协议,如 "mongodb://127.0.0.1:27017"
	var MOGODB_URI = "127.0.0.1:27017"
	//连接
	session, err := (MOGODB_URI)
	//连接失败时终止
	if err != nil {
        panic(err)
    }
	//延迟关闭,释放资源
	defer ()
	//设置模式
    (, true)
	//选择数据库与集合
    c := ("adatabase").C("acollection")
    //插入文档
    err = (&Person{Name:"Ale", Phone:"+55 53 8116 9639"},
               &Person{Name:"Cla",  Phone:"+55 53 8402 8510"})
	//出错判断
    if err != nil {
            (err)
    }
	//查询文档
    result := Person{}
    //注意mongodb存储后的字段大小写问题
    err = ({"name": "Ale"}).One(&result)
    //出错判断
    if err != nil {
        (err)
    }
    ("Phone:", )
})