yysg

导航

 

 获取

go get github.com/gin-gonic/gin

 你好

package main

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

func main() {
    //gin.Default() 创建一个路由handle
    r := gin.Default()
    //添加/hello路由,method为get,r.GET第一个参数为相对路径,第二个参数为处理函数
    r.GET("/hello", func(c *gin.Context) {
        //使用c.JSON,第一个参数为状态码,第二个为gin.H
        c.JSON(200, gin.H{
            "message": "你好",
        })
    })
    //启动,监听8000
    r.Run(":8000")
}

 使用GET、POST、PUT、PATCH、DELETE和OPTIONS

func main() {
	// 取消控制台debug颜色
	// gin.DisableConsoleColor()

	// 创建一个默认的路由handle
	router := 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)

	// 默认监听端口为8000,router.Run(":3000"),修改为监听3000端口
	router.Run()
}
func getting(c *gin.Context) {
}
func posting(c *gin.Context) {
}
func putting(c *gin.Context) {
}
func deleting(c *gin.Context) {
}
func patching(c *gin.Context) {
}
func head(c *gin.Context) {
}
func options(c *gin.Context) {
}

 路径中的参数

package main

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

func main() {
	//创建一个路由handle
	r := gin.Default()

	//匹配/user/john,但不匹配/user/或者/user
	r.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(200, "name = %s", name)
	})

	//如果没有路由匹配/user/john,将重定向到/user/john/
	r.GET("/user/:name/*action", func(c *gin.Context) {
		name := c.Param("name")
		action := c.Param("action")
		c.String(200, "name = %s, action = %s", name, action)
	})

	//启动,监听8000
	r.Run(":8000")
}

 请求中的参数

func main() {
	//创建一个路由handle
	r := gin.Default()

	//DefaultQuery可以设置默认值,当参数不存在时使用默认值
	r.GET("/user/", func(c *gin.Context) {
		name := c.DefaultQuery("name", "john")
		action := c.Query("action")
		c.String(200, "name = %s, action = %s", name, action)
	})

	//启动,监听8000
	r.Run(":8000")
}

 Post form

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func main() {
	//创建一个路由handle
	r := gin.Default()

	//适用于Content-Type为form-data、x-www-form-urlencoded
	r.POST("/form_post", func(c *gin.Context) {
		message := c.PostForm("message")
		nick := c.DefaultPostForm("nick", "anonymous")
		fmt.Println(message, nick)
		c.JSON(200, gin.H{
			"status": "posted",
			"message": message,
			"nick": nick,
		})
	})
	//启动,监听8000
	r.Run(":8000")
}

 请求 + Post form

package main

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

func main() {
	//创建一个路由handle
	r := gin.Default()

	//query + post form
	r.POST("/form_post", func(c *gin.Context) {
		first := c.Query("first")
		last := c.DefaultQuery("last", "last")
		message := c.PostForm("message")
		nick := c.DefaultPostForm("nick", "anonymous")
		c.JSON(200, gin.H{
			"status": "posted",
			"message": message,
			"nick": nick,
			"first": first,
			"last": last,
		})
	})
	//启动,监听8000
	r.Run(":8000")
}

 文件上传

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
)

func main() {
	//创建一个路由handle
	r := gin.Default()

	//文件上传,打印文件名
	r.POST("/upload", func(c *gin.Context) {
		file, _ := c.FormFile("file")
		log.Println(file.Filename)
		c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
	})
	//启动,监听8000
	r.Run(":8000")
}

 curl请求

curl.exe 127.0.0.1:8000/upload -F "file=@./a.txt" -H "Content-Type: multipart/form-data"

 多文件上传

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
)

func main() {
	//创建一个路由handle
	r := gin.Default()

	//多文件上传,打印文件数
	r.POST("/upload", func(c *gin.Context) {
		form, _ := c.MultipartForm()
		files := form.File["uploads"]
		for _, file := range files {
			log.Println(file.Filename)
		}
		c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
	})
	//启动,监听8000
	r.Run(":8000")
}

 路由组

package main

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

func main() {
	//创建一个路由handle
	r := gin.Default()

	//组1
	g1 := r.Group("/g1")
	{
		g1.GET("/login", func(c *gin.Context) {
		})
		g1.POST("/form", func(c *gin.Context) {
		})
	}
	//组2
	g2 := r.Group("/g2")
	{
		g2.GET("/login", func(c *gin.Context) {
		})
		g2.POST("/form", func(c *gin.Context) {
		})
	}

	//启动,监听8000
	r.Run(":8000")
}

 中间件

package main

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

//自定义中间件
func MyMiddle() gin.HandlerFunc {
	return func(c *gin.Context) {

	}
}

func AuthRequired() gin.HandlerFunc {
	return func(c *gin.Context) {
	}
}

func main() {
	//关闭控制台颜色
	gin.DisableConsoleColor()

	//创建一个路由handle
	r := gin.New()

	//加载日志模块,记录gin.DefaultWriter,默认指向os.Stdout
	r.Use(gin.Logger())

	//错误后,不退出main进程,相当于对panic做了处理
	r.Use(gin.Recovery())

	//对路径添加中间件
	r.GET("/mpath", MyMiddle(), func(c *gin.Context) {
	})

	//对组添加中间件
	authorized := r.Group("/")
	authorized.Use(AuthRequired())
	{
		authorized.POST("/login", func(c *gin.Context){
		})
		authorized.POST("/submit", func(c *gin.Context){
		})
		authorized.POST("/read", func(c *gin.Context){
		})

		// 嵌套组
		testing := authorized.Group("/testing")
		testing.GET("/analytics", func(c *gin.Context){
		})
	}
	//启动,监听8000
	r.Run(":8000")
}

 将日志写入文件

package main

import (
	"io"
	"os"
	//"fmt"
	"github.com/gin-gonic/gin"
	//"log"
	//"net/http"
)

func main() {
	//关闭控制台颜色
	gin.DisableConsoleColor()

	//创建日志文件
	f, _ := os.Create("a.log")
	//需在创建路由handle前
	gin.DefaultWriter = io.MultiWriter(f)

	//创建一个路由handle
	r := gin.Default()
	r.GET("/hello", func(c *gin.Context) {
		c.String(200, "nihao")
	})

	//启动,监听8000
	r.Run(":8000")
}

 格式绑定

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

// 绑定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 err := c.ShouldBindJSON(&json); err == 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"})
			}
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	// 绑定HTML表格(User=manu&Password=123)
	router.POST("/loginForm", func(c *gin.Context) {
		var form Login
		if err := c.ShouldBind(&form); err == 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"})
			}
		} else {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		}
	})

	//启动,监听8080
	router.Run(":8080")
}

curl请求

curl -v   http://localhost:8080/loginJSON   -H 'content-type: application/json'   -d '{"User": "manu", "Password": "123"}'

 复选框绑定

package main

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

type myForm struct {
    Colors []string `form:"colors[]"`
}

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

    r.LoadHTMLGlob("views/*")
    r.GET("/", indexHandler)
    r.POST("/", formHandler)

    r.Run(":8000")
}

func indexHandler(c *gin.Context) {
    c.HTML(200, "form.html", nil)
}

func formHandler(c *gin.Context) {
    var fakeForm myForm
    c.Bind(&fakeForm)
    c.JSON(200, gin.H{"color": fakeForm.Colors})
}
<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>

 表格绑定

package main

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

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.ShouldBindWith(&form, binding.Form)
		// or you can simply use autobinding with ShouldBind method:
		var form LoginForm
		// in this case proper binding will be automatically selected
		if c.ShouldBind(&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(":8000")
}
curl -v --form user=user --form password=password http://localhost:8000/login

 XML、JSON、YAML的渲染

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

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:8000
	r.Run(":8000")
}

 SecureJSON

package main

import (
	"net/http"

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

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

	// You can also use your own secure json prefix
	// r.SecureJsonPrefix(")]}',\n")

	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(":8000")
}

 静态文件

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

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(":8000")
}

 HTML渲染

 例1

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	router.LoadHTMLGlob("templates/*")
	//router.LoadHTMLFiles("templates/template1.tmpl", "templates/template2.html")
	router.GET("/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{
			"title": "Main website",
		})
	})
	router.Run(":8000")
}
<html>
	<h1>
		{{ .title }}
	</h1>
</html>

 例2

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

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(":8000")
}
{{ define "posts/index.tmpl" }}
<html><h1>
	{{ .title }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}
{{ define "users/index.tmpl" }}
<html><h1>
	{{ .title }}
</h1>
<p>Using users/index.tmpl</p>
</html>
{{ end }}

 自定义模板渲染

package main

import (
	"html/template"
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	html := template.Must(template.ParseFiles("templates/index.tmpl"))
	router.SetHTMLTemplate(html)
        //在index.tmpl中定义为test后可在调用时直接使用test
	router.GET("/test",func(c *gin.Context) {
		c.HTML(200, "test", gin.H{
			"title": "Users",
		})
	})
	router.Run(":8000")
}
{{ define "test" }}
<html>
	<h1>
		{{ .title }}
	</h1>
</html>
{{ end }}

 自定义分隔符

 r := gin.Default()
 //templates中,使用{[{}]}代替原来的{[]}
 r.Delims("{[{", "}]}")
 r.LoadHTMLGlob("/path/to/templates"))

 自定义模板函数

import (
	"fmt"
	"html/template"
	"net/http"
	"time"
	"github.com/gin-gonic/gin"
)

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("templates/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(":8000")
}
Date: {[{.now | formatAsDate}]}

 多模板继承

https://github.com/gin-contrib/multitemplate

 重定向

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

func main() {
	router := gin.Default()
	router.GET("/test", func(c *gin.Context) {
		c.Redirect(http.StatusMovedPermanently, "http://www.google.com/")
	})
	router.Run(":8000")
}

 自定义中间件

package main

import (
	"log"
	"time"
	"github.com/gin-gonic/gin"
)

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)
		c.String(200, "abc")
	})

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

 基础认证中间件

package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

// 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]string
	authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{
		"foo":    "bar",
		"austin": "1234",
		"lena":   "hello2",
		"manu":   "4321",
	}))

	// /admin/secrets endpoint
	// hit "127.0.0.1:8000/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:8000
	r.Run(":8000")
}

 并发

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

	r.GET("/long_async", func(c *gin.Context) {
		// create copy to be used inside the goroutine
		cCp := c.Copy()
		go func() {
			// simulate a long task with time.Sleep(). 5 seconds
			time.Sleep(5 * time.Second)

			// note that you are using the copied context "cCp", IMPORTANT
			log.Println("Done! in path " + cCp.Request.URL.Path)
		}()
	})

	r.GET("/long_sync", func(c *gin.Context) {
		// simulate a long task with time.Sleep(). 5 seconds
		time.Sleep(5 * time.Second)

		// since we are NOT using a goroutine, we do not have to copy the context
		log.Println("Done! in path " + c.Request.URL.Path)
	})

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

自定义http配置

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

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

支持加密

package main

import (
	"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 main

import (
	"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))
}

 多服务端

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
)

var (
	g errgroup.Group
)

func router01() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code":  http.StatusOK,
				"error": "Welcome server 01",
			},
		)
	})

	return e
}

func router02() http.Handler {
	e := gin.New()
	e.Use(gin.Recovery())
	e.GET("/", func(c *gin.Context) {
		c.JSON(
			http.StatusOK,
			gin.H{
				"code":  http.StatusOK,
				"error": "Welcome server 02",
			},
		)
	})

	return e
}

func main() {
	server01 := &http.Server{
		Addr:         ":8080",
		Handler:      router01(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	server02 := &http.Server{
		Addr:         ":8081",
		Handler:      router02(),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	g.Go(func() error {
		return server01.ListenAndServe()
	})

	g.Go(func() error {
		return server02.ListenAndServe()
	})

	if err := g.Wait(); err != nil {
		log.Fatal(err)
	}
}

 优雅的重启和关闭

https://github.com/fvbock/endless

 测试

 net/http/httptest

package main

func setupRouter() *gin.Engine {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.String(200, "pong")
	})
	return r
}

func main() {
	r := setupRouter()
	r.Run(":8080")
}

 代码测试 

package main

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestPingRoute(t *testing.T) {
	router := setupRouter()

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/ping", nil)
	router.ServeHTTP(w, req)

	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "pong", w.Body.String())
}
posted on 2018-02-03 14:14  yysg  阅读(601)  评论(1)    收藏  举报