Gin框架

打印 上一主题 下一主题

主题 907|帖子 907|积分 2721

Gin

环境:https://goproxy.cn,driect
github.com/gin-gonic/gin
介绍

Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API,性能要好得多,多亏了 httprouter,速度提高了 40 倍。 如果您需要性能和良好的生产力,您一定会喜欢 Gin。
在本节中,我们将介绍 Gin 是什么,它解决了哪些问题,以及它如何帮助你的项目。
或者, 如果你已经准备在项目中使用 Gin,请访问快速入门.
源码分析

  1. type Handler interface {
  2.         ServeHTTP(ResponseWriter, *Request)
  3. }
复制代码
实现

  1. // ServeHTTP conforms to the http.Handler interface.
  2. func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  3.    c := engine.pool.Get().(*Context)
  4.    c.writermem.reset(w)
  5.    c.Request = req
  6.    c.reset()
  7.    engine.handleHTTPRequest(c)
  8.    engine.pool.Put(c)
  9. }
复制代码

  • 通过对象池来减少内存申请和GC回收的消耗
  • 取出来要用的时候再初始化
<img alt="gin" loading="lazy">
特性

快速
基于 Radix 树的路由,小内存占用。没有反射。可预测的 API 性能。
支持中间件
传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如:Logger,Authorization,GZIP,最终操作 DB。
Crash 处理
Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样,你的服务器将始终可用。例如,你可以向 Sentry 报告这个 panic!
JSON 验证
Gin 可以解析并验证请求的 JSON,例如检查所需值的存在。
路由组
更好地组织路由。是否需要授权,不同的 API 版本…… 此外,这些组可以无限制地嵌套而不会降低性能。
错误管理
Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终,中间件可以将它们写入日志文件,数据库并通过网络发送。
内置渲染
Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API。
可扩展性
新建一个中间件非常简单,去查看示例代码吧。
快速入门

  1. package main
  2. import "github.com/gin-gonic/gin"
  3. func main() {
  4.         r := gin.Default()
  5.         r.GET("/ping", func(c *gin.Context) {
  6.                 c.JSON(200, gin.H{
  7.                         "message": "pong",
  8.                 })
  9.         })
  10.         r.Run(":8000")// 监听并在 0.0.0.0:8080 上启动服务
  11. }
复制代码

  • gin.Default()默认使用了Logger和Recover中间件
  • Logger是负责进行打印输出日志的中间件,方便开发者进行程序的调试
  • Recover如果程序执行过程中遇到了panic中断了服务,则Recover会恢复程序的运行并返回500的内部错误。
Engine

  1. type Engine struct {
  2.         RouterGroup
  3.         RedirectTrailingSlash bool
  4.         RedirectFixedPath bool
  5.         HandleMethodNotAllowed bool
  6.         ForwardedByClientIP bool
  7.         AppEngine bool
  8.         UseRawPath bool
  9.         UnescapePathValues bool
  10.         RemoveExtraSlash bool
  11.         RemoteIPHeaders []string
  12.         TrustedPlatform string
  13.         MaxMultipartMemory int64
  14.         delims           render.Delims
  15.         secureJSONPrefix string
  16.         HTMLRender       render.HTMLRender
  17.         FuncMap          template.FuncMap
  18.         allNoRoute       HandlersChain
  19.         allNoMethod      HandlersChain
  20.         noRoute          HandlersChain
  21.         noMethod         HandlersChain
  22.         pool             sync.Pool
  23.         trees            methodTrees
  24.         maxParams        uint16
  25.         maxSections      uint16
  26.         trustedProxies   []string
  27.         trustedCIDRs     []*net.IPNet
  28. }
复制代码
请求处理

HTTP 协议的 8 种请求类型介绍

HTTP 协议中共定义了八种方法或者叫“动作”来表明对Request-URI指定的资源的不同操作方式,具体介绍如下:

  • OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。
  • HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
  • GET:向特定的资源发出请求。
  • POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改。
  • PUT:向指定资源位置上传其最新内容。
  • DELETE:请求服务器删除 Request-URI 所标识的资源。
  • TRACE:回显服务器收到的请求,主要用于测试或诊断。
  • CONNECT:HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
通用处理

Handle方法

  1. func (group *RouterGroup)Handle(httpMethod,relativePath string,handler...Handler)
复制代码

  • httpMethod:表示要处理的HTTP请求类型,8种请求方式之一
  • relativePath:表示要解析的接口,由开发者定义
  • handlers:处理对应的请求的代码定义
Restful风格的API



  • gin支持Restful风格的API
  • 即Representational State Transfer的缩写。直接翻译的意思是”表现层状态转化”,是一种互联网应用程序的API设计理念:URL定位资源,用HTTP描述操作
1.获取文章 /blog/getXxx Get blog/Xxx
2.添加 /blog/addXxx POST blog/Xxx
3.修改 /blog/updateXxx PUT blog/Xxx
4.删除 /blog/delXxxx DELETE blog/Xxx
GET请求处理

路径参数- /:xx - Param("xx")

对于类似这样的请求:http://127.0.0.1:8080/index/12,那么如何获取最后路径中12的值呢?
  1. package main
  2. import (
  3.     "fmt"
  4.     "github.com/gin-gonic/gin"
  5.     "net/http"
  6. )
  7. func Index(ctx *gin.Context) {
  8.     id := ctx.Param("id")
  9.     fmt.Println(id)
  10.     ctx.String(http.StatusOK, "success!")
  11. }
  12. func main() {
  13.     router := gin.Default()
  14.    
  15.     // 路径参数获取,如:http://127.0.0.1:8080/index/12,获取12
  16.     router.GET("/index/:id", Index)
  17.     router.Run(":8080")
  18. }
复制代码
在挂载路由时需要通过":"来进行匹配,然后在视图函数中通过ctx.Param方法获取。
查询参数-/hello?xx=..? -Query()

对于类似这样的请求:http://127.0.0.1:8080/index1?id=12,那么如何获取最后路径中12的值呢?
1、ctx.Query
传参:http://127.0.0.1:8080/index1?id=12
路由:router.GET("/index1", Index1)
视图函数获取:ctx.Query("id")
2、ctx.DefaultQuery
传参:http://127.0.0.1:8080/index2
路由:router.GET("/index2", Index2)
视图函数获取:ctx.DefaultQuery("id", "0")
如果没有获取到id,就得到默认值0.
3、ctx.QueryArray
传参:http://127.0.0.1:8080/index3?id=1,2,3,4,5
路由:router.GET("/index3", Index3)
视图函数获取:ctx.QueryArray("id")
4、ctx.QueryMap
传参:http://127.0.0.1:8080/index4?user[name]="lily"&user[age]=15
路由:router.GET("/index4", Index4)
视图函数获取:ctx.QueryMap("user")
通用参数匹配  /user/:name/*action

当我们需要动态参数的路由时,如 /user/:id,通过调用不同的参数 :id 动态获取相应的用户信息。其中 /user/:id/*type,*type 的参数为可选。
  1. package main
  2. import (
  3.     "net/http"
  4.     "strings"
  5.     "github.com/gin-gonic/gin"
  6. )
  7. func main() {
  8.     r := gin.Default()
  9.     r.GET("/user/:name/*action", func(c *gin.Context) {
  10.         name := c.Param("name")
  11.         action := c.Param("action")
  12.         //截取/
  13.         action = strings.Trim(action, "/")
  14.         c.String(http.StatusOK, name+" is "+action)
  15.     })
  16.     //默认为监听8080端口
  17.     r.Run(":8000")
  18. }
复制代码
正常的结果:
  1. http://localhost:8080/api/hjz/HJZ114152
  2. hjz is HJZ114152
复制代码
注释掉:Trim()后
  1. http://localhost:8080/api/hjz/HJZ114152
  2. hjz is /HJZ114152
复制代码
POST请求处理

表单传输为post请求,http常见的传输格式为四种:

  • application/json
  • application/x-www-form-urlencoded
  • application/xml
  • multipart/form-data
表单参数可以通过PostForm()方法获取,该方法默认解析的是x-www-form-urlencoded或from-data格式的参数
普通方式提交表单-post -PostForm("xxx")

1、ctx.PostForm

  • 表单
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6. </head>
  7. <body>
  8. <form action="/post_index" method="post">
  9.     <p>用户名:<input type="text" name="username"></p>
  10.     <p>密 码:<input type="password" name="password"></p>
  11.     <p><input type="submit"></p>
  12. </form>
  13. </body>
  14. </html>
复制代码

  • 后台处理
  1. ...
  2. func PostIndex(ctx *gin.Context)  {
  3.     username := ctx.PostForm("username")
  4.     password := ctx.PostForm("password")
  5.     fmt.Printf("用户名:%s, 密码:%s", username, password)
  6.     ctx.String(http.StatusOK, "提交成功!")
  7. }
  8. ...
复制代码
2、ctx.PostFormMap

  • 表单
  1.         Title<!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6. </head>
  7. <body>
  8. <form action="/post_index" method="post">
  9.     <p>用户名:<input type="text" name="username"></p>
  10.     <p>密 码:<input type="password" name="password"></p>
  11.     <p><input type="submit"></p>
  12. </form>
  13. </body>
  14. </html>
复制代码

  • 后台处理
  1. ...
  2. func PostIndex1(ctx *gin.Context)  {
  3.     userMap := ctx.PostFormMap("user")
  4.     fmt.Println(userMap)
  5.     ctx.String(http.StatusOK, "提交成功!")
  6. }
  7. ...
复制代码
3、ctx.DefaultPostForm、ctx.PostFormArray

  • 表单
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6. </head>
  7. <body>
  8. <form action="/post_index2" method="post">
  9.     <p>用户名:<input type="text" name="username"></p>
  10.     <p>密 码:<input type="password" name="password"></p>
  11.     <p>爱 好:
  12.         读书<input type="checkbox" name="hobby" value="1">
  13.         看电影<input type="checkbox" name="hobby" value="2">
  14.         音乐<input type="checkbox" name="hobby" value="3">
  15.     </p>
  16.     <p><input type="submit"></p>
  17. </form>
  18. </body>
  19. </html>
复制代码

  • 后台处理
  1. ...
  2. func PostIndex2(ctx *gin.Context)  {
  3.     username := ctx.PostForm("username")
  4.     password := ctx.PostForm("password")
  5.     age := ctx.DefaultPostForm("age", "0")
  6.     hobby := ctx.PostFormArray("hobby")
  7.     fmt.Printf("用户名:%s, 密码:%s, 年龄:%s, 爱好:%s", username, password, age, hobby)
  8.     ctx.String(http.StatusOK, "提交成功!")
  9. }
  10. ...
复制代码
例子

  1. package main
  2. import (
  3.     "fmt"
  4.     "github.com/gin-gonic/gin"
  5.     "net/http"
  6. )
  7. func GetIndex(ctx *gin.Context) {
  8.     ctx.HTML(http.StatusOK, "index.html", nil)
  9. }
  10. func PostIndex(ctx *gin.Context) {
  11.     username := ctx.PostForm("username")
  12.     password := ctx.PostForm("password")
  13.     fmt.Printf("用户名:%s, 密码:%s", username, password)
  14.     ctx.String(http.StatusOK, "提交成功!")
  15. }
  16. func GetIndex1(ctx *gin.Context) {
  17.     ctx.HTML(http.StatusOK, "index1.html", nil)
  18. }
  19. func PostIndex1(ctx *gin.Context) {
  20.     userMap := ctx.PostFormMap("user")
  21.     fmt.Println(userMap)
  22.     ctx.String(http.StatusOK, "提交成功!")
  23. }
  24. func GetIndex2(ctx *gin.Context) {
  25.     ctx.HTML(http.StatusOK, "index2.html", nil)
  26. }
  27. func PostIndex2(ctx *gin.Context) {
  28.     username := ctx.PostForm("username")
  29.     password := ctx.PostForm("password")
  30.     age := ctx.DefaultPostForm("age", "0")
  31.     hobby := ctx.PostFormArray("hobby")
  32.     fmt.Printf("用户名:%s, 密码:%s, 年龄:%s, 爱好:%s", username, password, age, hobby)
  33.     ctx.String(http.StatusOK, "提交成功!")
  34. }
  35. func main() {
  36.     router := gin.Default()
  37.     router.LoadHTMLGlob("template/*")
  38.     // ctx.PostForm
  39.     router.GET("/get_index", GetIndex)
  40.     router.POST("/post_index", PostIndex)
  41.     // ctx.PostFormMap
  42.     router.GET("/get_index1", GetIndex1)
  43.     router.POST("/post_index1", PostIndex1)
  44.     // ctx.DefaultPostForm、ctx.PostFormArray
  45.     router.GET("/get_index2", GetIndex2)
  46.     router.POST("/post_index2", PostIndex2)
  47.     router.Run(":8080")
  48. }
复制代码
Ajax方式提交表单

ajax的后台处理逻辑与普通的表单的提交的处理方式基本相同,只不过在返回的时候需要返回json数据,前台使用回调函数进行处理。

  • 前台
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6.    
  7. </head>
  8. <body>
  9. <form>
  10.     <p>用户名:<input id="username" type="text"></p>
  11.     <p>密码:<input id="password" type="password"></p>
  12.     <p><input type="button" value="提交" id="btn_submit"></p>
  13. </form>
  14. </body>
  15. </html>
复制代码

  • 后台
  1. package main
  2. import (
  3.     "fmt"
  4.     "github.com/gin-gonic/gin"
  5.     "net/http"
  6. )
  7. func GetIndex(ctx *gin.Context) {
  8.     ctx.HTML(http.StatusOK, "index.html", nil)
  9. }
  10. func PostIndex(ctx *gin.Context) {
  11.     username := ctx.PostForm("username")
  12.     password := ctx.PostForm("password")
  13.     fmt.Println(username, password)
  14.     data := map[string]interface{}{
  15.         "code":    2000,
  16.         "message": "成功",
  17.     }
  18.     ctx.JSON(http.StatusOK, data)
  19. }
  20. func main() {
  21.     router := gin.Default()
  22.     router.LoadHTMLGlob("template/*")
  23.     router.Static("/static", "static")
  24.     router.GET("/get_index", GetIndex)
  25.     router.POST("/post_index", PostIndex)
  26.     router.Run(":8080")
  27. }
复制代码
参数绑定

无论时get请求的参数还是post请求的请求体,在后台都需要通过对应的方法来获取对应参数的值,那么有没有一种方式能够让我们定义好请求数据的格式,然后自动进行获取,这里可以通过参数绑定的方式来进行处理。它能够基于请求自动提取JSON、form表单和QueryString类型的数据,并把值绑定到指定的结构体对象
这里以get请求的查询参数为例:

  • 请求格式
  1. http://127.0.0.1:8080/index?username=%22llkk%22&password=%22123%22
复制代码

  • 后台处理
  1. package main
  2. import (
  3.     "fmt"
  4.     "github.com/gin-gonic/gin"
  5.     "net/http"
  6. )
  7. type User struct {
  8.     Username string `form:"username" json:"username"`
  9.     Password string `form:"password" json:"password"`
  10. }
  11. func Index(ctx *gin.Context) {
  12.     var user User
  13.     err := ctx.ShouldBind(&user)
  14.     fmt.Println(err)
  15.     fmt.Println(user.Username, user.Password) // "llkk" "123"
  16.     ctx.String(http.StatusOK, "success")
  17. }
  18. func main() {
  19.     router := gin.Default()
  20.     router.GET("/index", Index)
  21.     router.Run(":8080")
  22. }
复制代码
文件处理

上传单个文件



  • multipart/form-data格式用于文件上传
  • gin文件上传与原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7.     <title>Document</title>
  8. </head>
  9. <body>
  10.     <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
  11.           上传文件:<input type="file" name="file" >
  12.           <input type="submit" value="提交">
  13.     </form>
  14. </body>
  15. </html>
复制代码
[code]package mainimport (    "github.com/gin-gonic/gin")func main() {    r := gin.Default()    //限制上传最大尺寸    r.MaxMultipartMemory = 8
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

兜兜零元

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表