上一节咱们用Gin框架快速搭建了一个GET请求的接口,今天来学习路由和参数的获取。前端
熟悉RESTful
的同窗应该知道,RESTful
是网络应用程序的一种设计风格和开发方式,每个URI表明一种资源,客户端经过POST
、DELETE
、PUT
、GET
四种请求方式来对资源作增删改查的操做。git
一样的,Gin框架给咱们提供的除这4种动词外,还有PATCH
、OPTION
、HEAD
等,详细内容能够查看rentergroup.go
文件的IRoutes
接口。github
type IRoutes interface {
Use(...HandlerFunc) IRoutes
Handle(string, string, ...HandlerFunc) IRoutes
Any(string, ...HandlerFunc) IRoutes
GET(string, ...HandlerFunc) IRoutes
POST(string, ...HandlerFunc) IRoutes
DELETE(string, ...HandlerFunc) IRoutes
PATCH(string, ...HandlerFunc) IRoutes
PUT(string, ...HandlerFunc) IRoutes
OPTIONS(string, ...HandlerFunc) IRoutes
HEAD(string, ...HandlerFunc) IRoutes
StaticFile(string, string) IRoutes
Static(string, string) IRoutes
StaticFS(string, http.FileSystem) IRoutes
}复制代码
由于RenterGroup
实现了IRoutes
定义的全部请求动词,并且gin.Default
返回的Engine
类型继承了RenterGroup
,因此使用起来很是简单,只须要经过gin.Default
实例化对象,接下来全部的路由操做都经过该对象使用便可。golang
func main() {
router := gin.Default()
router.POST("/article", func(c *gin.Context) {
c.String(200, "article post")
})
router.DELETE("/article", func(c *gin.Context) {
c.String(200, "article delete")
})
router.PUT("/article", func(c *gin.Context) {
c.String(200, "article put")
})
router.GET("/article", func(c *gin.Context) {
c.String(200, "article get")
})
router.Run()
}复制代码
请求动词的第一个参数是请求路径,第二个参数是用于逻辑处理的函数,能够是匿名的或是其余地方定义的函数名。不一样的请求动词能够定义相同的路径,只须要切换动词就能够进入对应的处理逻辑。shell
curl -X PUT http://localhost:8080/article
curl -X POST http://localhost:8080/article
curl -X GET http://localhost:8080/article
curl -X DELETE http://localhost:8080/article复制代码
GET请求有两种,一种是在URL后加上?name=pingye
,这种是有参数名的,另外一种是在路径中直接加上参数值/article/1
,这种没有参数名,须要在代码中解析参数。数组
protocol://hostname:[port]/path/[query]#fragment复制代码
咱们先来看路由携带参数值的玩法,这里有一道题,怎么利用Gin获取下面连接的参数值1
。服务器
实现方式很是简单,只须要在路由中设置好占位符:id
,冒号为占位符的标志,冒号后面的参数名能够自定义,Gin会将路由与请求地址进行匹配,若匹配成功会将1
赋值为占位符:id
,只需调用c.Param
就能够获取id
的值。网络
router.GET("/article/:id", func(c *gin.Context) {
id := c.Param("id")
c.String(200, id)
})复制代码
可是,:id
占位符会存在一个问题,若是id
参数值传空就会有404
的错误提示。app
因而Gin提供了另外一种占位符*id
,使用它就能够达到取空值的目的。框架
router.GET("/article/*id", func(c *gin.Context) {
id := c.Param("id")
c.String(200, id)
})复制代码
除了路由携带参数值外,接下来看比较传统的GET
传参方式。
http://localhost:8080/welcome?firstname=Jane&lastname=Doe复制代码
能够经过c.Query
或c.DefaultQuery
方法获取问号后的参数。
router.GET("/welcome", func(c *gin.Context) {
firstname := c.DefaultQuery("firstname", "pingyeaa")
lastname := c.Query("lastname")
c.String(200, firstname+" "+lastname)
})复制代码
这二者最终都调用了GetQuery
方法,惟一的区别是DefaultQuery
作了默认值处理。
func (c *Context) DefaultQuery(key, defaultValue string) string {
if value, ok := c.GetQuery(key); ok {
return value
}
return defaultValue
}
func (c *Context) Query(key string) string {
value, _ := c.GetQuery(key)
return value
}复制代码
从HTML提交过来的表单form
内容一样也能够轻松获取。
router.POST("/form_post", func(c *gin.Context) {
message := c.PostForm("message")
nick := c.DefaultPostForm("nick", "anonymous")
c.JSON(200, gin.H{
"status": "posted",
"message": message,
"nick": nick,
})
})复制代码
curl -d "message=pingye" http://localhost:8080/form_post
{"message":"pingye","nick":"anonymous","status":"posted"}复制代码
有时候(例如复选框)前端页面会传来数组类型的值,这种类型name
相同,但存储的内容不一样。
POST /post?ids[a]=1234&ids[b]=hello HTTP/1.1
Content-Type: application/x-www-form-urlencoded复制代码
依然是一个QueryMap
方法就搞定,该方法默认返回map
类型。
router.GET("/post", func(c *gin.Context) {
ids := c.QueryMap("ids")
c.String(200, ids["a"]+" "+ids["b"])
})复制代码
curl http://localhost:8080/post?ids[a]=pingye&ids[b]=hehe
pingye hehe复制代码
通常状况下,文件上传会由前端直接传给云存储服务商,好比阿里云、七牛云等,比较少的场景会传给本身的服务器。为了不书到用时方恨少
的状况发生,咱们来了解一下。
Gin提供了FormFile
方法获取文件流,这个方法返回了一个FileHeader
类型的变量,能够调用Filename
属性来查看文件名。
type FileHeader struct {
Filename string
Header textproto.MIMEHeader
Size int64
content []byte
tmpfile string
}复制代码
router.POST("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
c.String(200, file.Filename)
})复制代码
经过curl
请求接口,能够看到轻松获取文件名称。
curl -X POST http://localhost:8080/upload \
-F "file=@/Users/enoch/Downloads/IMG_9216.JPG" \
-H "Content-Type: multipart/form-data"
IMG_9216.JPG复制代码
固然不止能够拿到文件名,咱们还可使用SaveUploadedFile
方法将文件保存到某个地方,文件保存时要确保有目标目录的操做权限。
router.POST("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
c.String(200, file.Filename)
err := c.SaveUploadedFile(file, "/Users/enoch/Desktop/ab.png")
if err != nil {
c.String(500, err.Error())
}
})复制代码
当接口发生重大变动(好比入参出参)时,考虑到向下兼容,通常会新增一个接口,可是又但愿新接口的名称显而易见地看出是老接口的升级版,那么就能够在接口名前加上版本号v1/article
这种形式。
v1 := r.Group("v1")
{
v1.POST("/login", func(c *gin.Context) {
c.String(200, "v1/login")
})
v1.POST("/submit", func(c *gin.Context) {
c.String(200, "v1/submit")
})
}
v2 := r.Group("v2")
{
v2.POST("/login", func(c *gin.Context) {
c.String(200, "v2/login")
})
v2.POST("/submit", func(c *gin.Context) {
c.String(200, "v2/submit")
})
}复制代码
curl -X POST http://localhost:8080/v1/login
curl -X POST http://localhost:8080/v2/login复制代码
Go语言库代码示例,欢迎star github.com/pingyeaa/go…
感谢你们的观看,若是以为文章对你有所帮助,欢迎关注公众号「平也」,聚焦Go语言与技术原理。