打赏

golang gin框架

gin框架使用

1.安装

go get gopkg.in/gin-gonic/gin.v1

2.简单的HTTP服务

package main

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

func main() {
	// 1.创建一个路由handler,默认带有 Logger 和 Recovery 两个中间件
	engine := gin.Default()
	// 2.通过HTTP方法绑定路由规则和路由函数
	engine.GET("/", func(ctx *gin.Context) {
		ctx.String(http.StatusOK, "hello world")
	})
	// 3.启动路由的Run方法监听端口
	engine.Run(":8080")
}

3.GET请求的参数获取

3.1 获取GET请求路由的参数

(1.) 冒号:加上一个参数名组成路由参数。可以使用c.Params的方法读取其值。

路由:http://127.0.0.1:8080/user/jone
-------------------------------------------------
// 冒号:加上一个参数名组成路由参数,可以获取到请求参数,请求路径如:/user/zhangsan
engine.GET("/user/:name", func(ctx *gin.Context) {
// 使用c.Params的方法读取其值,类型为string
name := ctx.Param("name")
ctx.String(http.StatusOK, "hello %s", name)  // 输出:hello jone
})

(2.) 除了冒号,gin还提供了星号处理参数,*号能匹配的规则就更多

星号:匹配可有可无,但需保留最后的/,否则会报404,如:
http://127.0.0.1:8080/user/jone/
http://127.0.0.1:8080/user/jone/play
------------------------------------------------------------
engine.GET("/user/:name/*action", func(ctx *gin.Context) {
    // 使用c.Params的方法读取其值,类型为string
    name := ctx.Param("name")
    action := ctx.Param("action")
    ctx.String(http.StatusOK, "hello %s,action:%s", name, action) // 输出:hello jone,action:/play
})

(3.)GET请求URL中通过key=value的形式,可通过c.Query()获取

// 请求示例:http://127.0.0.1:8080/welcome?first_name=tom&last_name=lucy
engine.GET("/welcome", func(ctx *gin.Context) {
	// 使用c.DefaultQuery方法读取参数,其中当参数不存在的时候,提供一个默认值
	first_name := ctx.DefaultQuery("first_name", "jone")
	// 使用Query方法读取正常参数,当参数不存在的时候,返回空字串
	last_name := ctx.Query("last_name")
	ctx.String(http.StatusOK, "first_name: %s,last_name: %s", first_name, last_name) // 输出:first_name: tom,last_name: lucy
})

4.Post请求参数获取

4.1 form表单数据获取
// form表单数据获取,请求示例:
// curl -X POST http://127.0.0.1:8080/form_post -H "Content-Type:application/x-www-form-urlencoded" -d "message=hello&nick=rsj217" | python -m json.tool
------------------------------------------------------------------------
engine.POST("/form_post", func(ctx *gin.Context) {
	message := ctx.PostForm("message")
	// c.PostFROM解析的是x-www-form-urlencoded或from-data的参数。
	nick := ctx.DefaultPostForm("nick", "anonymous")
	// 调用c.JSON则返回json数据,其中gin.H封装了生成json的方式
	ctx.JSON(http.StatusOK, gin.H{
		"status": gin.H{
		"status_code": 200,
		"status":      "ok",
		},
		"message": message,
		"nick":    nick,
	})
})
4.2 文件上传
// 单个文件上传,测试:curl -X POST http://127.0.0.1:8000/upload -F "upload=@/Users/ghost/Desktop/pic.jpg" -H "Content-Type: multipart/form-data"
----------------------------------------------------------------------------------
engine.POST("/upload", func(ctx *gin.Context) {
	//name := ctx.PostForm("name")
	// 使用c.Request.FormFile解析客户端文件name属性
	file, header, err := ctx.Request.FormFile("upload")
	if err != nil {
		ctx.String(http.StatusBadRequest, "bad request")
		return
	}
	// 从header中获取文件名
	fileName := header.Filename
	// 创建文件
	out, err := os.Create(fileName)
	if err != nil {
		ctx.String(http.StatusInternalServerError, "create file failed")
		return
	}
	defer out.Close()
	// 使用os的操作,把文件数据复制到硬盘上
	_, err = io.Copy(out, file)
	if err != nil {
		ctx.String(http.StatusInternalServerError, "io copy failed")
		return
	}
	ctx.String(http.StatusCreated, "upload success")
})

上传多个文件:

router.POST("/multi/upload", func(c *gin.Context) {
        err := c.Request.ParseMultipartForm(200000)
        if err != nil {
            log.Fatal(err)
        }
		// 使用了c.Request.MultipartForm得到文件句柄
        formdata := c.Request.MultipartForm 
		// 获取文件数据
        files := formdata.File["upload"] 
        // 遍历文件读写
        for i, _ := range files {
            file, err := files[i].Open()
            defer file.Close()
            if err != nil {
                log.Fatal(err)
            }

            out, err := os.Create(files[i].Filename)
            defer out.Close()
            if err != nil {
                log.Fatal(err)
            }
            _, err = io.Copy(out, file)
            if err != nil {
                log.Fatal(err)
            }
            c.String(http.StatusCreated, "upload successful")
        }
    })
4.3 数据绑定

(1.)使用ctx.BindJSON()或者ctx.BindWith()

// 数据绑定,测试:curl -X POST http://127.0.0.1:8080/login -H "Content-Type:application/x-www-form-urlencoded" -d "username=jone&password=123&age=21" | python -m json.tool
	engine.POST("/login", func(ctx *gin.Context) {
		var user User
		var err error
		contentType := ctx.Request.Header.Get("Content-Type")
		switch contentType {
		case "application/json":
			err = ctx.BindJSON(&user)
		case "application/x-www-form-urlencoded":
			err = ctx.BindWith(&user, binding.Form)
		}
		if err != nil {
			log.Fatal(err)
		}
		ctx.JSON(http.StatusOK, gin.H{
			"user":     user.UserName,
			"password": user.Password,
			"age":      user.Age,
		})
	})

(2.)使用c.Bind()函数

// 使用c.Bind会根据content-type自动推断绑定的参数类型
	engine.POST("/login2", func(c *gin.Context) {
		var user User

		err := c.Bind(&user)
		if err != nil {
			fmt.Println(err)
			log.Fatal(err)
		}

		c.JSON(http.StatusOK, gin.H{
			"username":   user.UserName,
			"password":     user.Password,
			"age":        user.Age,
		})

4.4 格式渲染

 router.GET("/render", func(c *gin.Context) {
        contentType := c.DefaultQuery("content_type", "json")
        if contentType == "json" {
        // JSON格式渲染
            c.JSON(http.StatusOK, gin.H{
                "user":   "rsj217",
                "passwd": "123",
            })
        } else if contentType == "xml" {
        // XML格式渲染
            c.XML(http.StatusOK, gin.H{
                "user":   "rsj217",
                "passwd": "123",
            })
        }

    })

4.5 重定向

router.GET("/redict/google", func(c *gin.Context) {
     c.Redirect(http.StatusMovedPermanently, "https://google.com")
 })

4.6 分组路由

v1 := router.Group("/v1")
v1.GET("/login", func(c *gin.Context) {
      c.String(http.StatusOK, "v1 login")
 })

v2 := router.Group("/v2")
v2.GET("/login", func(c *gin.Context) {
     c.String(http.StatusOK, "v2 login")
 })

4.7 中间件

(1.) 中间件函数

func MiddleWare() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Println("before middleware")
        // 设置请求
        c.Set("request", "clinet_request")
        c.Next()
        fmt.Println("before middleware")
    }
}

(2.)中间件定义

// 使用中间件,调用中间件函数
router.Use(MiddleWare())
{
    router.GET("/middleware", func(c *gin.Context) {
       request := c.MustGet("request").(string)
       // 获取请求
       req, _ := c.Get("request")
       c.JSON(http.StatusOK, gin.H{
              "middile_request": request,
              "request": req,
        })
     })
}

(3.)单个路由中间件

router.GET("/before", MiddleWare(), func(c *gin.Context) {
        request := c.MustGet("request").(string)
        c.JSON(http.StatusOK, gin.H{
            "middile_request": request,
        })
 })
 
 // 使用全局CORS中间件。
 // router.Use(Cors())
 
 //rate-limit 中间件
 lmt := tollbooth.NewLimiter(1, nil)
 lmt.SetMessage("服务繁忙,请稍后再试...")

(4.) 群组中间件

authorized := router.Group("/", MyMiddelware())
// 或者这样用:
authorized := router.Group("/")
authorized.Use(MyMiddelware())
{
    authorized.POST("/login", loginEndpoint)
}

(5.) 使用中间件进行接口鉴权

  router.GET("/auth/signin", func(c *gin.Context) {
        cookie := &http.Cookie{
            Name:     "session_id",
            Value:    "123",
            Path:     "/",
            HttpOnly: true,
        }
        http.SetCookie(c.Writer, cookie)
        c.String(http.StatusOK, "Login successful")
    })
	// 使用中间件AuthMiddleWare注册之后,将会先执行AuthMiddleWare的逻辑,然后才到/home的逻辑
    router.GET("/home", AuthMiddleWare(), func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"data": "home"})
    })
-----------------------------------------------------------------------    
func AuthMiddleWare() gin.HandlerFunc {
    return func(c *gin.Context) {
        if cookie, err := c.Request.Cookie("session_id"); err == nil {
            value := cookie.Value
            fmt.Println(value)
            if value == "123" {
                c.Next()
                return
            }
        }
        c.JSON(http.StatusUnauthorized, gin.H{
            "error": "Unauthorized",
        })
        c.Abort()
        return
    }
}

4.8 自定义router

func main() {
    router := gin.Default()
    http.ListenAndServe(":8080", router)
}
--------------------------------------------------------
func main() {
    router := gin.Default()
    // router.Run(":80")
    // 这样写就可以了,下面所有代码(go1.8+)是为了优雅处理重启等动作。
    srv := &http.Server{
        Addr:         ":80",
        Handler:      router,
        ReadTimeout:  30 * time.Second,
        WriteTimeout: 30 * time.Second,
    }
    go func() {
        // 监听请求
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s\n", err)
        }
    }()
    // 优雅Shutdown(或重启)服务
    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt) // syscall.SIGKILL
    <-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)
    }
    select {
    case <-ctx.Done():
    }   
    log.Println("Server exiting")
}

4.9 静态资源加载

router := gin.Default()
// 静态资源加载,本例为css,js以及资源图片
router.StaticFS("/public", http.Dir("D:/tmm/website/static"))
router.StaticFile("/favicon.ico", "./resources/favicon.ico")
// 通过 router.LoadHTMLGlob("website/tpl//") 导入模板根目录下所有的文件
router.LoadHTMLGlob("website/tpl/*/*")
// Listen and serve on 0.0.0.0:80
router.Run(":80")

参考链接

https://www.jianshu.com/p/a31e4ee25305

posted @ 2022-04-18 18:04  苍山落暮  阅读(459)  评论(0编辑  收藏  举报