Gin_ルート

参照:

https://www.chaindesk.cn/witbook/19/329

https://www.liwenzhou.com/posts/Go/Gin_framework/

1.ネット/ HTTP

1.1ファイル戻し

2.ジンの枠組み

package main

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

/*
1、router:=gin.Default():这是默认的服务器。使用gin的Default方法创建一个路由Handler;
2、然后通过Http方法绑定路由规则和路由函数。不同于net/http库的路由函数,gin进行了封装,把request和response都封装到了gin.Context的上下文环境中。
3、最后启动路由的Run方法监听端口。还可以用http.ListenAndServe(":8080", router),或者自定义Http服务器配置。
*/

func main() {
	// 创建一个默认的路由引擎
	r := gin.Default() //带有默认中间件的路由
	//engine := New() //不带中间件的路由

	// GET:请求方式;/hello:请求的路径
	// 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数
	r.GET("/hello", func(c *gin.Context) {
		// c.JSON:返回JSON格式的数据
		//gin.H --> type H map[string]interface{}
		c.JSON(200, gin.H{
			"message": "Hello world!",
		})
	})
	// 启动HTTP服务,默认在0.0.0.0:8080启动服务
	r.Run()
	//也可以使用下面的方式启动服务
	//http.ListenAndServe(":8080", router)


}

//default源码
func Default() *Engine {
	debugPrintWARNINGDefault()
	engine := New() //不带中间件的路由
	engine.Use(Logger(), Recovery())
	return engine
}

//Run源码
func (engine *Engine) Run(addr ...string) (err error) {
	defer func() { debugPrintError(err) }()

	address := resolveAddress(addr)
	debugPrint("Listening and serving HTTP on %s\n", address)
	err = http.ListenAndServe(address, engine) //engine就是r := gin.Default()
	return
}

3. RESTful API

对调试不友好,可以使用postman调试

4. 路由

4.1 基本路由

基本路由 gin 框架中采用的路由库是 httprouter。

// 创建带有默认中间件的路由:
// 日志与恢复中间件
router := gin.Default()
//创建不带中间件的路由:
//r := gin.New()

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)

4.1 API参数

gin的路由来自httprouter库。因此httprouter具有的功能,gin也具有,不过gin不支持路由正则表达式。

冒号:加上一个参数名组成路由参数。可以使用c.Params的方法读取其值。当然这个值是字串string。

除了:,gin还提供了*号处理参数,*号能匹配的规则就更多。

package main

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


func main() {
	r := gin.Default()
	r.GET("/user/:name/*action", func(c *gin.Context) {
		name := c.Param("name")
		action := c.Param("action")
		message := name + " is " + action
		c.String(http.StatusOK, message)
	})
	r.Run()
}

4.2 URL参数

web提供的服务通常是client和server的交互。其中客户端向服务器发送请求,除了路由参数,其他的参数无非两种,查询字符串query string和报文体body参数。所谓query string,即路由用,用?以后连接的key1=value2&key2=value2的形式的参数。当然这个key-value是经过urlencode编码。

URL 参数通过 DefaultQuery 或 Query 方法获取。

对于参数的处理,经常会出现参数不存在的情况,对于是否提供默认值,gin也考虑了,并且给出了一个优雅的方案,使用c.DefaultQuery方法读取参数,其中当参数不存在的时候,提供一个默认值。使用Query方法读取正常参数,当参数不存在的时候,返回空字串。

package main

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

func main() {
	router := gin.Default()
	router.GET("/welcome", func(c *gin.Context) {
		name := c.DefaultQuery("name", "Guest") //可设置默认值
		//nickname := c.Query("nickname") // 是 c.Request.URL.Query().Get("nickname") 的简写
		c.String(http.StatusOK, fmt.Sprintf("Hello %s ", name))
	})
	router.Run(":9527")

}

4.3 表单参数

http的报文体传输数据就比query string稍微复杂一点,常见的格式就有四种。例如application/jsonapplication/x-www-form-urlencodedapplication/xmlmultipart/form-data。后面一个主要用于图片上传。json格式的很好理解,urlencode其实也不难,无非就是把query string的内容,放到了body体里,同样也需要urlencode。默认情况下,c.PostFROM解析的是x-www-form-urlencodedfrom-data的参数。

表单参数通过 PostForm 方法获取:

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"fmt"
)
func main() { router := gin.Default() //form router.POST("/form", func(c *gin.Context) { type1 := c.DefaultPostForm("type", "alert") //可设置默认值 username := c.PostForm("username") password := c.PostForm("password") //hobbys := c.PostFormMap("hobby") //hobbys := c.QueryArray("hobby") hobbys := c.PostFormArray("hobby") c.String(http.StatusOK, fmt.Sprintf("type is %s, username is %s, password is %s,hobby is %v", type1, username, password,hobbys)) }) router.Run(":9527") }

使用PostForm形式,注意必须要设置Post的type,同时此方法中忽略URL中带的参数,所有的参数需要从Body中获得。

4.4 文件上传

上传单个文件

前面介绍了基本的发送数据,其中multipart/form-data转用于文件上传。gin文件上传也很方便,和原生的net/http方法类似,不同在于gin把原生的request封装到c.Request中了。

package main

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

func main() {
	router := gin.Default()
	// Set a lower memory limit for multipart forms (default is 32 MiB)
	// router.MaxMultipartMemory = 8 << 20  // 8 MiB
	router.POST("/upload", func(c *gin.Context) {
		// single file
		file, _ := c.FormFile("file")
		log.Println(file.Filename)

		// Upload the file to specific dst.
		// func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error {}
		c.SaveUploadedFile(file, file.Filename)

		/*
		也可以直接使用io操作,拷贝文件数据。
		out, err := os.Create(filename)
		defer out.Close()
		_, err = io.Copy(out, file)
		*/

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

上传多个文件

所谓多个文件,无非就是多一次遍历文件,然后一次copy数据存储即可。

package main

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

func main() {
	router := gin.Default()
	// Set a lower memory limit for multipart forms (default is 32 MiB)
	router.MaxMultipartMemory = 8 << 20 // 8 MiB
	//router.Static("/", "./public")
	router.POST("/upload", func(c *gin.Context) {

		// Multipart form
		form, err := c.MultipartForm()
		if err != nil {
			c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
			return
		}
		files := form.File["files"]

		for _, file := range files {
			if err := c.SaveUploadedFile(file, file.Filename); err != nil {
				c.String(http.StatusBadRequest, fmt.Sprintf("upload file err: %s", err.Error()))
				return
			}
		}

		c.String(http.StatusOK, fmt.Sprintf("Uploaded successfully %d files ", len(files)))
	})
	router.Run(":8080")
}

 与单个文件上传类似,只不过使用了c.Request.MultipartForm得到文件句柄,再获取文件数据,然后遍历读写。

5. 路由组

我们可以将拥有共同URL前缀的路由划分为一个路由组。习惯性一对{}包裹同组的路由,这只是为了看着清晰,你用不用{}包裹功能上没什么区别。

func main() {
	r := gin.Default()
	userGroup := r.Group("/user")
	{
		userGroup.GET("/index", func(c *gin.Context) {...})
		userGroup.GET("/login", func(c *gin.Context) {...})
		userGroup.POST("/login", func(c *gin.Context) {...})

	}
	shopGroup := r.Group("/shop")
	{
		shopGroup.GET("/index", func(c *gin.Context) {...})
		shopGroup.GET("/cart", func(c *gin.Context) {...})
		shopGroup.POST("/checkout", func(c *gin.Context) {...})
	}
	r.Run()
}

路由组也是支持嵌套的,例如:

shopGroup := r.Group("/shop")
	{
		shopGroup.GET("/index", func(c *gin.Context) {...})
		shopGroup.GET("/cart", func(c *gin.Context) {...})
		shopGroup.POST("/checkout", func(c *gin.Context) {...})
		// 嵌套路由组
		xx := shopGroup.Group("xx")
		xx.GET("/oo", func(c *gin.Context) {...})
	}

  

 

おすすめ

転載: www.cnblogs.com/yzg-14/p/12381375.html