Gin Web框架简单介绍
翻译自: https://github.com/gin-gonic/gin/blob/develop/README.md
Gin Web框架
Gin是用Golang实现的一种Web框架。基于 httprouter,它提供了相似martini但更好性能(路由性能约快40倍)的API服务. 假设你希望构建一个高性能的生产环境,你会喜欢上使用 Gin。
$ cat test.go
package mainimport "github.com/gin-gonic/gin"func main() {r := gin.Default()r.GET("/ping", func(c *gin.Context) {c.JSON(200, gin.H{"message": "pong",})})r.Run() // listen and server on 0.0.0.0:8080
}
基准測试
Gin基于HttpRouter的这个定制版本号来构建。
查看所有測试
Benchmark name | (1) | (2) | (3) | (4) |
---|---|---|---|---|
BenchmarkAce_GithubAll | 10000 | 109482 | 13792 | 167 |
BenchmarkBear_GithubAll | 10000 | 287490 | 79952 | 943 |
BenchmarkBeego_GithubAll | 3000 | 562184 | 146272 | 2092 |
BenchmarkBone_GithubAll | 500 | 2578716 | 648016 | 8119 |
BenchmarkDenco_GithubAll | 20000 | 94955 | 20224 | 167 |
BenchmarkEcho_GithubAll | 30000 | 58705 | 0 | 0 |
BenchmarkGin_GithubAll | 30000 | 50991 | 0 | 0 |
BenchmarkGocraftWeb_GithubAll | 5000 | 449648 | 133280 | 1889 |
BenchmarkGoji_GithubAll | 2000 | 689748 | 56113 | 334 |
BenchmarkGoJsonRest_GithubAll | 5000 | 537769 | 135995 | 2940 |
BenchmarkGoRestful_GithubAll | 100 | 18410628 | 797236 | 7725 |
BenchmarkGorillaMux_GithubAll | 200 | 8036360 | 153137 | 1791 |
BenchmarkHttpRouter_GithubAll | 20000 | 63506 | 13792 | 167 |
BenchmarkHttpTreeMux_GithubAll | 10000 | 165927 | 56112 | 334 |
BenchmarkKocha_GithubAll | 10000 | 171362 | 23304 | 843 |
BenchmarkMacaron_GithubAll | 2000 | 817008 | 224960 | 2315 |
BenchmarkMartini_GithubAll | 100 | 12609209 | 237952 | 2686 |
BenchmarkPat_GithubAll | 300 | 4830398 | 1504101 | 32222 |
BenchmarkPossum_GithubAll | 10000 | 301716 | 97440 | 812 |
BenchmarkR2router_GithubAll | 10000 | 270691 | 77328 | 1182 |
BenchmarkRevel_GithubAll | 1000 | 1491919 | 345553 | 5918 |
BenchmarkRivet_GithubAll | 10000 | 283860 | 84272 | 1079 |
BenchmarkTango_GithubAll | 5000 | 473821 | 87078 | 2470 |
BenchmarkTigerTonic_GithubAll | 2000 | 1120131 | 241088 | 6052 |
BenchmarkTraffic_GithubAll | 200 | 8708979 | 2664762 | 22390 |
BenchmarkVulcan_GithubAll | 5000 | 353392 | 19894 | 609 |
BenchmarkZeus_GithubAll | 2000 | 944234 | 300688 | 2648 |
(1): 总反复次数
(2): 单次请求耗时 (ns/op)
(3): 堆内存大小 (B/op)
(4): 单次请求内存分配数 (allocs/op)
Gin v1. stable
- [x] 零分配路由.
- [x] 从路由到写请求, 依旧为最快的路由器和框架.
- [x] 完备的单元測试套件.
- [x] Battle tested.(?
)
- [x] API冻结, 新的release版不会影响现有的代码.
高速開始
下载并安装Gin:
$ go get github.com/gin-gonic/gin
在代码中import进来:
import "github.com/gin-gonic/gin"
(可选) Import
net/http
. 假设用到诸如http.StatusOK
的常量, 须要引入该包:import "net/http"
API演示样例
使用 GET, POST, PUT, PATCH, DELETE 以及 OPTIONS
func main() {// Creates a gin router with default middleware:// logger and recovery (crash-free) middlewarerouter := gin.Default()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)// By default it serves on :8080 unless a// PORT environment variable was defined.router.Run()// router.Run(":3000") for a hard coded port
}
路径參数
func main() {router := gin.Default()// This handler will match /user/john but will not match neither /user/ or /userrouter.GET("/user/:name", func(c *gin.Context) {name := c.Param("name")c.String(http.StatusOK, "Hello %s", name)})// However, this one will match /user/john/ and also /user/john/send// If no other routers match /user/john, it will redirect to /user/john/router.GET("/user/:name/*action", func(c *gin.Context) {name := c.Param("name")action := c.Param("action")message := name + " is " + actionc.String(http.StatusOK, message)})router.Run(":8080")
}
查询字符串參数
func main() {router := gin.Default()// Query string parameters are parsed using the existing underlying request object.// The request responds to a url matching: /welcome?firstname=Jane&lastname=Doerouter.GET("/welcome", func(c *gin.Context) {firstname := c.DefaultQuery("firstname", "Guest")lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname")c.String(http.StatusOK, "Hello %s %s", firstname, lastname)})router.Run(":8080")
}
Multipart/Urlencoded表单提交
func main() {router := gin.Default()router.POST("/form_post", func(c *gin.Context) {message := c.PostForm("message")nick := c.DefaultPostForm("nick", "anonymous")c.JSON(200, gin.H{"status": "posted","message": message,"nick": nick,})})router.Run(":8080")
}
很多其它演示样例: 查询參数 + POST表单提交
POST /post?id=1234&page=1 HTTP/1.1
Content-Type: application/x-www-form-urlencodedname=manu&message=this_is_great
func main() {router := gin.Default()router.POST("/post", func(c *gin.Context) {id := c.Query("id")page := c.DefaultQuery("page", "0")name := c.PostForm("name")message := c.PostForm("message")fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)})router.Run(":8080")
}
id: 1234; page: 1; name: manu; message: this_is_great
很多其它演示样例: 上传文件
參考问题 #548.
func main() {router := gin.Default()router.POST("/upload", func(c *gin.Context) {file, header , err := c.Request.FormFile("upload")filename := header.Filenamefmt.Println(header.Filename)out, err := os.Create("./tmp/"+filename+".png")if err != nil {log.Fatal(err)}defer out.Close()_, err = io.Copy(out, file)if err != nil {log.Fatal(err)}})router.Run(":8080")
}
分组路由
func main() {router := gin.Default()// Simple group: v1v1 := router.Group("/v1"){v1.POST("/login", loginEndpoint)v1.POST("/submit", submitEndpoint)v1.POST("/read", readEndpoint)}// Simple group: v2v2 := router.Group("/v2"){v2.POST("/login", loginEndpoint)v2.POST("/submit", submitEndpoint)v2.POST("/read", readEndpoint)}router.Run(":8080")
}
不使用中间件, 使用Gin默认配置
使用
r := gin.New()
来取代
r := gin.Default()
使用中间件
func main() {// Creates a router without any middleware by defaultr := gin.New()// Global middlewarer.Use(gin.Logger())r.Use(gin.Recovery())// Per route middleware, you can add as many as you desire.r.GET("/benchmark", MyBenchLogger(), benchEndpoint)// Authorization group// authorized := r.Group("/", AuthRequired())// exactly the same as:authorized := r.Group("/")// per group middleware! in this case we use the custom created// AuthRequired() middleware just in the "authorized" group.authorized.Use(AuthRequired()){authorized.POST("/login", loginEndpoint)authorized.POST("/submit", submitEndpoint)authorized.POST("/read", readEndpoint)// nested grouptesting := authorized.Group("testing")testing.GET("/analytics", analyticsEndpoint)}// Listen and server on 0.0.0.0:8080r.Run(":8080")
}
model binding与验证
要绑定一个请求body到某个类型, 能够使用model binding。 眼下支持JSON, XML 以及标准from格式 (foo=bar&boo=baz)的绑定。
所有你想要绑定的域(field)。 须要你设置相应的绑定标识。 比如, 要绑定到JSON, 则这样声明json:"fieldname"
。
使用Bind方法时, Gin会尝试通过Content-Type头部来推定绑定的类型(如json还是form)。而假设你明白知道要绑定的类型, 能够使用BindWith方法。
你也能够指定哪些filed须要绑定。 假设某个filed像这样声明: binding:"required"
, 那么在进行绑定时假设发现是空值(注: 是请求中不存在该field名?), 当前的请求会失败并收到错误提示。
// 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()// Example for binding JSON ({"user": "manu", "password": "123"})router.POST("/loginJSON", func(c *gin.Context) {var json Loginif 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"})}}})// Example for binding a HTML form (user=manu&password=123)router.POST("/loginForm", func(c *gin.Context) {var form Login// This will infer what binder to use depending on the content-type header.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"})}}})// Listen and server on 0.0.0.0:8080router.Run(":8080")
}
Multipart/Urlencoded表单请求方式的绑定
package mainimport ("github.com/gin-gonic/gin""github.com/gin-gonic/gin/binding"
)type LoginForm struct {User string `form:"user" binding:"required"`Password string `form:"password" binding:"required"`
}func main() {router := gin.Default()router.POST("/login", func(c *gin.Context) {// you can bind multipart form with explicit binding declaration:// c.BindWith(&form, binding.Form)// or you can simply use autobinding with Bind method:var form LoginForm// in this case proper binding will be automatically selectedif 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"})}}})router.Run(":8080")
}
使用下面命令測试:
$ curl -v --form user=user --form password=password http://localhost:8080/login
XML和JSON的渲染
func main() {r := gin.Default()// gin.H is a shortcut for map[string]interface{}r.GET("/someJSON", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})})r.GET("/moreJSON", func(c *gin.Context) {// You also can use a structvar msg struct {Name string `json:"user"`Message stringNumber int}msg.Name = "Lena"msg.Message = "hey"msg.Number = 123// Note that msg.Name becomes "user" in the JSON// Will output : {"user": "Lena", "Message": "hey", "Number": 123}c.JSON(http.StatusOK, msg)})r.GET("/someXML", func(c *gin.Context) {c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})})// Listen and server on 0.0.0.0:8080r.Run(":8080")
}
处理静态文件的请求
func main() {router := gin.Default()router.Static("/assets", "./assets")router.StaticFS("/more_static", http.Dir("my_file_system"))router.StaticFile("/favicon.ico", "./resources/favicon.ico")// Listen and server on 0.0.0.0:8080router.Run(":8080")
}
HTML模板渲染
Using LoadHTMLTemplates()
func main() {router := gin.Default()router.LoadHTMLGlob("templates/*")//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")router.GET("/index", func(c *gin.Context) {c.HTML(http.StatusOK, "index.tmpl", gin.H{"title": "Main website",})})router.Run(":8080")
}
templates/index.tmpl
<html><h1>{{ .title }}</h1>
</html>
使用不同路径下但同样文件名称的模板
func main() {router := gin.Default()router.LoadHTMLGlob("templates/**/*")router.GET("/posts/index", func(c *gin.Context) {c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{"title": "Posts",})})router.GET("/users/index", func(c *gin.Context) {c.HTML(http.StatusOK, "users/index.tmpl", gin.H{"title": "Users",})})router.Run(":8080")
}
templates/posts/index.tmpl
{{ define "posts/index.tmpl" }}
<html><h1>{{ .title }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}
templates/users/index.tmpl
{{ define "users/index.tmpl" }}
<html><h1>{{ .title }}
</h1>
<p>Using users/index.tmpl</p>
</html>
{{ end }}
你也能够使用自己的渲染模板
import "html/template"func main() {router := gin.Default()html := template.Must(template.ParseFiles("file1", "file2"))router.SetHTMLTemplate(html)router.Run(":8080")
}
重定向
实现HTTP重定向并不麻烦:
r.GET("/test", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
})
内部或外部的地址都是支持的。
定制中间件
func Logger() gin.HandlerFunc {return func(c *gin.Context) {t := time.Now()// Set example variablec.Set("example", "12345")// before requestc.Next()// after requestlatency := time.Since(t)log.Print(latency)// access the status we are sendingstatus := c.Writer.Status()log.Println(status)}
}func main() {r := gin.New()r.Use(Logger())r.GET("/test", func(c *gin.Context) {example := c.MustGet("example").(string)// it would print: "12345"log.Println(example)})// Listen and server on 0.0.0.0:8080r.Run(":8080")
}
使用 BasicAuth() 中间件
// simulate some private data
var secrets = gin.H{"foo": gin.H{"email": "foo@bar.com", "phone": "123433"},"austin": gin.H{"email": "austin@example.com", "phone": "666"},"lena": gin.H{"email": "lena@guapa.com", "phone": "523443"},
}func main() {r := gin.Default()// Group using gin.BasicAuth() middleware// gin.Accounts is a shortcut for map[string]stringauthorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{"foo": "bar","austin": "1234","lena": "hello2","manu": "4321",}))// /admin/secrets endpoint// hit "localhost:8080/admin/secretsauthorized.GET("/secrets", func(c *gin.Context) {// get user, it was set by the BasicAuth middlewareuser := 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 server on 0.0.0.0:8080r.Run(":8080")
}
中间件中的Goroutines
在一个middleware或handler中使用goroutine时, 你不能直接使用源gin.Context, 而仅仅能使用它的一份仅仅读拷贝。
func main() {r := gin.Default()r.GET("/long_async", func(c *gin.Context) {// create copy to be used inside the goroutinecCp := c.Copy()go func() {// simulate a long task with time.Sleep(). 5 secondstime.Sleep(5 * time.Second)// note that you are using the copied context "cCp", IMPORTANTlog.Println("Done! in path " + cCp.Request.URL.Path)}()})r.GET("/long_sync", func(c *gin.Context) {// simulate a long task with time.Sleep(). 5 secondstime.Sleep(5 * time.Second)// since we are NOT using a goroutine, we do not have to copy the contextlog.Println("Done! in path " + c.Request.URL.Path)})// Listen and server on 0.0.0.0:8080r.Run(":8080")
}
自己定义HTTP配置
直接使用http.ListenAndServe()
。 演示样例:
func main() {router := gin.Default()http.ListenAndServe(":8080", router)
}
或者
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
,详情请參考#296。
router := gin.Default()
router.GET("/", handler)
// [...]
endless.ListenAndServe(":4242", router)
或者, 除使用endless之外的方法:
- manners: 一种平滑关闭自己的Go HTTP服务。
转载于:https://www.cnblogs.com/jzssuanfa/p/7268675.html
Gin Web框架简单介绍相关推荐
- Web Services简单介绍
Web Services简单介绍 Web Services入门 一.Web Services简介 1.什么是Web Services? Web Services 是应用程序组件 Web Service ...
- Django - Django框架 简单介绍
Django框架 简单介绍 本文地址: http://blog.csdn.net/caroline_wendy/article/details/29172271 1. 介绍 Django是一个开放源码 ...
- 【修真院Java小课堂】Tiles框架简单介绍
大家好,我是IT修真院上海分院第6期的学员,一枚正直纯洁善良的程序员 今天给大家分享一下,Tiles框架简单介绍 Tiles框架简单介绍 背景介绍 什么是Tiles Tiles 是一种JSP布局框架, ...
- soul框架简单介绍与设计模式分析
soul框架简单介绍与设计模式分析 1. 初识 1.1 查看官网文档了解 1.2. 目标: 2. 分析源码 2.1. 网关的实现原理 2.1.1. 跨域请求问题 2.1.2. 网关请求处理 2.1.3 ...
- Rebound动画框架简单介绍
Rebound动画框架简单介绍 Android菜鸟一枚,有不对的地方希望大家指出,谢谢. 最近在接手了一个老项目,发现里面动画框架用的是facebook中的Rebound框架,由于以前没听说过,放假时 ...
- Go gin web框架介绍
gin框架介绍 一.gin框架介绍 gin是用go语言开发的一个web框架,简单易用,是一个轻量级框架. 二.为什么选择gin 1.运行响应非常快 2.快速开发 3.文档齐全 4.社区活跃 三.特性 ...
- Spring 框架简单介绍
考虑到你可能不熟悉 Spring,我这里对它做下简单介绍.我们常说的 Spring 框架,是指 Spring Framework 基础框架.Spring Framework 是整个 Spring 生态 ...
- 玩转人工智能(3)常用的大数据框架简单介绍
时光不老,我们不散. 讲大数据框架前,简单的介绍下大数据的文化.信息时代人类社会的进步得益于分享和开源.大数据时代属于信息时代的第三代发展阶段(2001年到2011年可以认为是CT行业的黄金期,200 ...
- Go Gin web框架的路由原理及中间件原理
一.Gin框架的路由原理: 参考: go路由httprouter中的压缩字典树算法图解及c++实现 Golang-gin框架路由原理 首先了解下什么是路由? 简而言之,http路由即是一条http请求 ...
- python微型web框架flask介绍
Flask是一个基于python的,微型web框架.之所以被称为微型是因为其核心非常简单,同时具有很强的扩展能力.它几乎不给使用者做任何技术决定. 安装flask时应该注意其必须的几个支持包比如Jin ...
最新文章
- 8086内存分段理解
- python迭代数据类型_在大型数据集上自动迭代推断数据类型和最小项大小
- 使用jquery处理数据时要注意的问题
- Linux中sysstat服务,Linux 性能优化工具包 sysstat 以及 sysstat 服务
- 学习java技术有前途吗?当然有前途
- 81.游戏项目-物体任意角度飞行和停止
- 【Qt】Qt5.12版本编译Oracle驱动教程
- ubuntu - 如何以root身份使用图形界面管理文件?
- java io流操作_十个Demo进行讲解Java中IO流的常用操作~
- lua系列之 lua-cjson模块安装报错问题解决
- python从键盘输入一个字符串、将小写字母_# 每日一道面试题 # 从键盘输入一个字符串,将小写字母全部转换成大写字母,然后输出到一个磁盘文件test中保存。...
- 工业机器人综合教学实训平台
- 删除服务器远程桌面痕迹,清除3389连接后留下的日志,清除3389远程桌面连接记录...
- echarts柱状图及阴影偏移
- java开源项目地址
- NVIDIA Studio和Game Ready区别
- Redis之惰性删除
- 《游戏机制——高级游戏设计技术》一2.4 渐进型游戏
- Android手电筒介绍
- 《SQL与关系数据库理论——如何编写健壮的SQL代码》一3.7 TABLE_DUM和TABLE_DEE