github.com/gin-gonic/gin 中间件

https://www.jianshu.com/p/98965b3ff638/

github.com/gin-gonic/gin是一个轻量级的 WEB 框架,支持 RestFull 风格 API,支持 GET,POST,PUT,PATCH,DELETE,OPTIONS 等 http 方法,支持文件上传,分组路由,Multipart/Urlencoded FORM,以及支持 JsonP,参数处理等等功能,这些都和 WEB 紧密相关,通过提供这些功能,使开发人员更方便地处理 WEB 业务。

使用 GET, POST, PUT, PATCH, DELETE, OPTIONS

func main() {
    // Disable Console Color
    // gin.DisableConsoleColor()

    // 使用默认中间件创建一个gin路由器
    // logger and recovery (crash-free) 中间件
    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)

    // 默认启动的是 8080端口,也可以自己定义启动端口
    router.Run()
    // router.Run(":3000") for a hard coded port
}

项目中导入

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

导入NET/HTTP(可选)。例如,如果使用诸如HTTP.StasuCK之类的常数,则需要这样做。

import "net/http"

A demo:

package main

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

启动后,在浏览器输入:浏览其会渲染输出:

http://127.0.0.1:8080/ping

在这里插入图片描述
还可以用如下的方式,渲染浏览器页面输出字符串:

package main

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

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

	router.GET("/someGet",getting)
	router.Run()
}

func getting(c *gin.Context) {
	c.String(http.StatusOK,"Hello gin")
}

http://127.0.0.1:8080/someGet

在这里插入图片描述

我们点开源码发现,不管是渲染输出json格式、还是简单的字符串都是调用了c.Render方法,以下只是列出了2种,还有其他的诸如HTML、IndentedJSON、SecureJSON、JSONP、AsciiJSON、XML、YAML、ProtoBuf等。

func (c *Context) String(code int, format string, values ...interface{}) {
	c.Render(code, render.String{Format: format, Data: values})
}
func (c *Context) JSON(code int, obj interface{}) {
	c.Render(code, render.JSON{Data: obj})
}

获取路径中的参数:

package main

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

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

	// 此规则能够匹配/someGet/aaa这种格式,但不能匹配/usomeGet/ 或 /someGet这种格式
	router.GET("/someGet/:name",getting)

	// 但是,这个规则既能匹配/someGet/aaa/格式也能匹配/someGet/aaa/send这种格式
	// 如果没有其他路由器匹配/someGet/aaa,它将重定向到/someGet/aaa/
	router.GET("/someGet/:name/*action", func(c *gin.Context) {
		name := c.Param("name")
		action := c.Param("action")
		message := name + "is" + action
		c.String(http.StatusOK,message)
	})
	router.Run()
}

func getting(c *gin.Context) {
	name := c.Param("name")
	c.String(http.StatusOK,"Hello %s",name)
}

所以我们浏览器输入http://0.0.0.0:8080/someGet/aaaa可以
http://0.0.0.0:8080/someGet/或者http://0.0.0.0:8080/someGet都报错误

以上是一个参数,我们还可以定义多级参数。

http://127.0.0.1:8080/someGet/bbb

在这里插入图片描述
获取Get参数:

package main

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

func main() {
	router := gin.Default()
	// 匹配的url格式:  /someGet?firstname=Jane&lastname=Doe
	router.GET("/someGet",getting)
	router.Run()
}

func getting(c *gin.Context) {
	firstname := c.DefaultQuery("firstname","Guest")
	lastname := c.Query("lastname")
	c.String(http.StatusOK,"Hello: %s,%s",firstname,lastname)
}

浏览器输入http://127.0.0.1:8080/someGet?firstname=wyf&lastname=123
渲染页面输出为Hello wyf 123

浏览器输入http://127.0.0.1:8080/someGet?lastname=123,渲染页面输出为Hello Guest 123

http://127.0.0.1:8080/someGet?firstname=aaa&lastname=bbb

在这里插入图片描述

http://127.0.0.1:8080/someGet?lastname=123

在这里插入图片描述
获取Post 参数

package main

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

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

	router.POST("/someGet",getting)
	router.Run()
}

func getting(c *gin.Context) {
	message := c.PostForm("message")
	nick := c.DefaultPostForm("nick","anonymous") // 此方法可以设置默认值

	c.JSON(200,gin.H{
		"status":"posted",
		"message":message,
		"nick":nick,
	})
}

在这里插入图片描述
Get+Post 混合形式:

package main

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

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

	router.POST("/someGet",getting)
	router.Run()
}

func getting(c *gin.Context) {
	id := c.Query("id")
	page := c.DefaultQuery("page","0")
	name := c.PostForm("name")
	message := c.PostForm("message")

	c.String(http.StatusOK,"id: %s; page: %s; name: %s; message: %s",id,page,name,message)
}

在这里插入图片描述
构造Map格式:

package main

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

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

	router.POST("/someGet",getting)
	router.Run()
}

func getting(c *gin.Context) {
	ids := c.QueryMap("ids")
	names := c.PostFormMap("names")

	fmt.Printf("ids:%v; names:%v\n",ids,names)
	c.JSON(200,gin.H{
		"ids":ids,
		"names":names,
	})
	c.String(http.StatusOK,"ids:%v; names:%v",ids,names)
}

在这里插入图片描述
路由分组:

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")
}
package main

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

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

	v1 := router.Group("/v1")
	{
		v1.GET("/read",readEndpoint)
	}

	v2 := router.Group("/v2")
	{
		v2.GET("/login",loginEndpoint)
	}

	router.Run(":8080")
}

func readEndpoint(c *gin.Context) {
	fmt.Println("read")
}

func loginEndpoint(c *gin.Context) {
	fmt.Println("login")
}

浏览器输入http://127.0.0.1:8080/v1/read
后台log输出read

浏览器输入http://127.0.0.1:8080/v2/login
后台log输出login
在这里插入图片描述
上传文件
上传文件的文件名可以由用户自定义,所以可能包含非法字符串,为了安全起见,应该由服务端统一文件名规则。

单文件上传:

func main() {
    router := gin.Default()
    // 给表单限制上传大小 (默认 32 MiB)
    // router.MaxMultipartMemory = 8 << 20  // 8 MiB
    router.POST("/upload", func(c *gin.Context) {
        // 单文件
        file, _ := c.FormFile("file")
        log.Println(file.Filename)

        // 上传文件到指定的路径
        // c.SaveUploadedFile(file, dst)

        c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
    })
    router.Run(":8080")
}

curl 测试:

curl -X POST http://localhost:8080/upload \
  -F "file=@/Users/appleboy/test.zip" \
  -H "Content-Type: multipart/form-data"

多文件上传:

func main() {
    router := gin.Default()
    // 给表单限制上传大小 (默认 32 MiB)
    // router.MaxMultipartMemory = 8 << 20  // 8 MiB
    router.POST("/upload", func(c *gin.Context) {
        // 多文件
        form, _ := c.MultipartForm()
        files := form.File["upload[]"]

        for _, file := range files {
            log.Println(file.Filename)

            // 上传文件到指定的路径
            // c.SaveUploadedFile(file, dst)
        }
        c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
    })
    router.Run(":8080")
}

curl 测试:

curl -X POST http://localhost:8080/upload \
  -F "upload[]=@/Users/appleboy/test1.zip" \
  -F "upload[]=@/Users/appleboy/test2.zip" \
  -H "Content-Type: multipart/form-data"

中间件使用详解

无中间件启动:
使用r := gin.New() 代替r := gin.Default() // 默认启动方式,包含 Logger、Recovery 中间件

使用中间件:

func main() {
    // 创建一个不包含中间件的路由器
    r := gin.New()

    // 全局中间件
    // 使用 Logger 中间件
    r.Use(gin.Logger())

    // 使用 Recovery 中间件
    r.Use(gin.Recovery())

    // 路由添加中间件,可以添加任意多个
    r.GET("/benchmark", MyBenchLogger(), benchEndpoint)

    // 路由组中添加中间件
    // 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")
}

写日志文件:

func main() {
    // 禁用控制台颜色
    gin.DisableConsoleColor()

    // 创建记录日志的文件
    f, _ := os.Create("gin.log")
    gin.DefaultWriter = io.MultiWriter(f)

    // 如果需要将日志同时写入文件和控制台,请使用以下代码
    // gin.DefaultWriter = io.MultiWriter(f, os.Stdout)

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

    router.Run(":8080")
}

自定义日志格式

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

    // LoggerWithFormatter 中间件会将日志写入 gin.DefaultWriter
    // By default gin.DefaultWriter = os.Stdout
    router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {

        // 你的自定义格式
        return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
                param.ClientIP,
                param.TimeStamp.Format(time.RFC1123),
                param.Method,
                param.Path,
                param.Request.Proto,
                param.StatusCode,
                param.Latency,
                param.Request.UserAgent(),
                param.ErrorMessage,
        )
    }))
    router.Use(gin.Recovery())

    router.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })

    router.Run(":8080")
}

输出示例:

::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值