上一節咱們用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語言與技術原理。