Gin开发01
来源:互联网 发布:网络打假教程 编辑:程序博客网 时间:2024/06/09 16:50
Gin学习
1 基础环境
首先配置好go环境,设置好GOPATH环境变量。我的为例,输入go env
,输出如下:
C:\Users\Xin>go envset GOARCH=386set GOBIN=C:\go\bin // 必须设置set GOEXE=.exeset GOHOSTARCH=386set GOHOSTOS=windowsset GOOS=windowsset GOPATH=D:\go // 必须设置set GORACE=set GOROOT=C:\go // 必须设置set GOTOOLDIR=C:\go\pkg\tool\windows_386set GCCGO=gccgoset GO386=set CC=gccset GOGCCFLAGS=-m32 -mthreads -fmessage-length=0set CXX=g++set CGO_ENABLED=1set PKG_CONFIG=pkg-configset CGO_CFLAGS=-g -O2set CGO_CPPFLAGS=set CGO_CXXFLAGS=-g -O2set CGO_FFLAGS=-g -O2set CGO_LDFLAGS=-g -O2
然后,使用go下载gin库,go get github.com/gin-gonic/gin
,一般使用需要的依赖:
import "github.com/gin-gonic/gin"import "net/http"
2 Demo和学习记录
2.1 最简单的Demo
首先官方最简单的一个Demo:
// 文件名为 t1.gopackage 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 serve on 0.0.0.0:8080}
- 在
%GOPATH%\src
文件夹中创建一个自己的项目文件夹,比如 Demo1,然后新建一个go文件,如t1.go。将上述代码复制进入,保存。 - 新建CMD窗口,进入Demo1所在文件夹,然后输入
go run t1.go
将我们的代码运行起来。 - 在浏览器中输入
http://127.0.0.1:8080/ping
,浏览器如果有回复,则说明我们代码成功!
2.2 路由与参数获取
路由的几种方式:
- 绝对匹配。对/xxx
的GET/POST/DELETE/HEAD…请求的路由。
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) route.Any("/testing", startPage)
/user/:name
对二级名称关联name变量。/user/:name/*action
与上一个的区别是*
部分可以有,也可以没有,即可匹配/user/:name/
url。
现代化路由形式:
分组的路由:
func main() { router := gin.Default() // Simple group: v1 v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) v1.POST("/read", readEndpoint) } // Simple group: v2 v2 := router.Group("/v2") { v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) } router.Run(":8080")}
参数获取:
GET请求的参数获取:
func main() { router := gin.Default() // url matching: /welcome?firstname=Jane&lastname=Doe router.GET("/welcome", func(c *gin.Context) { firstname := c.DefaultQuery("firstname", "Guest") // 带有默认返回值的获取方式 lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname"), 可能为nil c.String(http.StatusOK, "Hello %s %s", firstname, lastname) }) router.Run(":8080")}
Multipart/UrlEncode表单:
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")}
当两种方式都存在时,可以混合使用。
文件上传:
单个文件:
func main() { router := gin.Default() router.POST("/upload", func(c *gin.Context) { // single file file, _ := c.FormFile("file") log.Println(file.Filename) // Upload the file to specific dst. // c.SaveUploadedFile(file, dst) c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) }) router.Run(":8080")}
多个文件:
func main() { router := gin.Default() router.POST("/upload", func(c *gin.Context) { // Multipart form form, _ := c.MultipartForm() files := form.File["upload[]"] for _, file := range files { log.Println(file.Filename) // Upload the file to specific dst. // c.SaveUploadedFile(file, dst) } c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files))) }) router.Run(":8080")}
2.3 中间件
在上面的代码中,我们创建gin的实例使用的是r := gin.Default()
里面开启了很多默认的中间件。如果你想使用一个干净的,没有任何中间件的gin实例,可以使用r := gin.New()
。
func main() { // Creates a router without any middleware by default r := gin.New() // Global middleware r.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 group testing := authorized.Group("testing") testing.GET("/analytics", analyticsEndpoint) } // Listen and serve on 0.0.0.0:8080 r.Run(":8080")}
2.4 数据绑定与验证
Gin支持绑定的数据格式为Json, XML, Url Param(foo=bar&boo=baz)。数据验证使用的是go-playground/validator.v8
。
// Binding from JSONtype 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 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"}) } } }) // 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 serve on 0.0.0.0:8080 router.Run(":8080")}
如果只绑定URL的字段,可以使用如下:
if c.BindQuery(&person) == nil { log.Println("====== Only Bind By Query String ======") log.Println(person.Name) log.Println(person.Address)}
如果POST和URL数据都需要:
// If `GET`, only `Form` binding engine (`query`) used.// If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`).// See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48if c.Bind(&person) == nil { log.Println(person.Name) log.Println(person.Address)}
绑定HTML中的checkboxes:
// HTML部分 <form action="/" method="POST"> <p>Check some colors</p> <label for="red">Red</label> <input type="checkbox" name="colors[]" value="red" id="red" /> <label for="green">Green</label> <input type="checkbox" name="colors[]" value="green" id="green" /> <label for="blue">Blue</label> <input type="checkbox" name="colors[]" value="blue" id="blue" /> <input type="submit" /></form>// go语言部分 type myForm struct { Colors []string `form:"colors[]"`}...func formHandler(c *gin.Context) { var fakeForm myForm c.Bind(&fakeForm) c.JSON(200, gin.H{"color": fakeForm.Colors})}
Multipart/Urlencoded的绑定:
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.MustBindWith(&form, binding.Form) // or you can simply use autobinding with Bind method: var form LoginForm // in this case proper binding will be automatically selected 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"}) } } }) router.Run(":8080")}
2.5 数据渲染
XML/JSON/YAML类型数据:
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 struct var msg struct { Name string `json:"user"` Message string Number 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}) }) r.GET("/someYAML", func(c *gin.Context) { c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080")}
SecureJSON:(原始JSON加前缀)
func main() { r := gin.Default() // You can also use your own secure json prefix r.SecureJsonPrefix("myTitle") // 默认是while(1); r.GET("/someJSON", func(c *gin.Context) { names := []string{"lena", "austin", "foo"} // Will output : while(1);["lena","austin","foo"] c.SecureJSON(http.StatusOK, names) }) // Listen and serve on 0.0.0.0:8080 r.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 serve on 0.0.0.0:8080 router.Run(":8080")}
HTML页面渲染:
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")}
2.6 自定义
自定义模版渲染:
import "html/template"func main() { router := gin.Default() html := template.Must(template.ParseFiles("file1", "file2")) router.SetHTMLTemplate(html) router.Run(":8080")}
自定义分隔符:
r := gin.Default()r.Delims("{[{", "}]}")r.LoadHTMLGlob("/path/to/templates"))
自定义模版函数:
func formatAsDate(t time.Time) string { year, month, day := t.Date() return fmt.Sprintf("%d%02d/%02d", year, month, day)}func main() { router := gin.Default() router.Delims("{[{", "}]}") router.SetFuncMap(template.FuncMap{ "formatAsDate": formatAsDate, }) router.LoadHTMLFiles("./fixtures/basic/raw.tmpl") router.GET("/raw", func(c *gin.Context) { c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), }) }) router.Run(":8080")}// taw.tmplDate: {[{.now | formatAsDate}]}
重定向:
r.GET("/test", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")})
2.7 自定义中间件
func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // Set example variable c.Set("example", "12345") // before request c.Next() // after request 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) { example := c.MustGet("example").(string) // it would print: "12345" log.Println(example) }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080")}
在定制中间件时,不要直接使用原始context,而要使用一个read-only的copy。
授权验证中间件:
// simulate some private datavar 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]string authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{ "foo": "bar", "austin": "1234", "lena": "hello2", "manu": "4321", })) // /admin/secrets endpoint // hit "localhost:8080/admin/secrets authorized.GET("/secrets", func(c *gin.Context) { // get user, it was set by the BasicAuth middleware 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")}
2.8 定制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()}
2.10 支持加密HTTPS
最简单的方式:
package mainimport ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin")func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) log.Fatal(autotls.Run(r, "example1.com", "example2.com"))}
自己管理证书的方式:
package mainimport ( "log" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" "golang.org/x/crypto/acme/autocert")func main() { r := gin.Default() // Ping handler r.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) m := autocert.Manager{ Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"), Cache: autocert.DirCache("/var/www/.cache"), } log.Fatal(autotls.RunWithManager(r, &m))}
2.11 优雅地关闭服务
// +build go1.8package mainimport ( "context" "log" "net/http" "os" "os/signal" "time" "github.com/gin-gonic/gin")func main() { router := gin.Default() router.GET("/", func(c *gin.Context) { time.Sleep(5 * time.Second) c.String(http.StatusOK, "Welcome Gin Server") }) srv := &http.Server{ Addr: ":8080", Handler: router, } go func() { // service connections if err := srv.ListenAndServe(); err != nil { log.Printf("listen: %s\n", err) } }() // Wait for interrupt signal to gracefully shutdown the server with // a timeout of 5 seconds. quit := make(chan os.Signal) signal.Notify(quit, os.Interrupt) <-quit log.Println("Shutdown Server ...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } log.Println("Server exist")}
- Gin开发01
- Gin开发02
- Gin开发03
- golang开发框架之gin
- gin框架
- 银河 Gin
- Gin安装
- gin中的断言写法
- Gin Web框架简介
- gin url树
- baby-gin 算法
- gin使用gzip压缩
- Gin框架初识
- Gin 框架源码笔记
- golang-gin框架笔记
- Gin html模板引用
- Go语言web框架 gin
- 【pg_rman】备份GIN索引bug
- Spring IOC SpEL 表达式
- 糖果传递 HAOI 2008 tuyvj 1924
- React学习笔记_react-redux原理分析
- JavaSE———类与对象
- 编译安装redis报错zmalloc.h
- Gin开发01
- 说说大型网站可伸缩性架构的设计原理
- zookeeper+dubbo管理控制台实践
- 解决页面使用overflow: scroll在iOS上滑动卡顿的问题
- AJAX基础XMLHttpReqiest
- 【入门篇】Activiti设置局部变量两种方法
- JZOJ 5441. 【NOIP2017提高A组冲刺11.1】序列
- (HDOJ)1001——超级楼梯(递推)
- 用 logstash 解析 json 数组