01 . Go框架之Gin框架從入門到熟悉(路由和上傳檔案)

men發表於2020-10-27

Gin框架簡介

Gin是使用Go/Golang語言實現的HTTP Web框架, 介面簡潔, 效能極高,截止1.4.0版本,包含測試程式碼,僅14K, 其中測試程式碼9K, 也就是說測試原始碼僅5k左右, 具有類似Martini的API, 效能更高-快40倍.

Gin特性
/*
		快速:  路由不使用反射,基於Radix樹,記憶體佔用少
		中介軟體: HTTP請求,先經過一系列中介軟體和最終操作來處理,例如: Logger, Authorization,GZIP等, 
					 這個特性和NodeJs的Koa框架很像, 中介軟體機制也極大的提高了框架的可擴充套件性.
		Cr			 
		異常處理:  服務始終可用, 不會當機,Gin可以捕獲panic,並恢復,而且極為便利的機制處理HTTP請求過程中發生的錯誤.
    JSON:  Gin可以解析並驗證請求的JSON, 這個特性對於Restful API的開發尤其有用.
    路由分組:  例如需要授權和不需要授權的API分組,不同版本的API分組.
    					而且分組可巢狀,且效能不受影響.
    渲染內建:  原生支援JSON, XML和HTML的渲染.
*/
安裝Gin
go get -u -v github.com/gin-gonic/gin

/*
		-v:列印出被構建的程式碼包的名字
		-u:已存在相關的程式碼包,強行更新程式碼包及其依賴包
*/
第一個Gin程式
package main

import "github.com/gin-gonic/gin"

func main()  {
	// 建立一個預設的路由引擎
	r := gin.Default()

	// GET:  請求方式: /hello:  請求的路徑
	// 當客戶端以GET的方法請求/hello路徑時,會執行後面的匿名函式
	r.GET("/hello", func(c *gin.Context) {
		
		// c.JSON:  返回JSON格式的資料
		c.JSON(200,gin.H{
			"message": "Hello World",
		})
	})
	
	// 啟動HTTP服務,預設在0.0.0.0:8080啟動服務
	r.Run()
}

/*
		1. 首先我們使用gin.Default()生成了一個例項,這個例項即WSGI應用程式.
		2. 接下來, 我們使用r.Get("/",...)宣告瞭一個路由,告訴Gin什麼樣的URL能觸發傳入的函式,
				這個函式返回我們想要顯示在使用者瀏覽器中的資訊.
				
		3. 最後用r.Run()函式讓應用執行在本地伺服器上,預設監聽埠是_8080_, 可以傳入引數,
				例如: r.Run(":9999")即執行在9999埠.
*/

路由

路由方法有GET, POST, PUT, PATCH, DELETEOPTIONS,還有Any,可匹配以上任意型別的請求

無引數
r.GET("/", func(c *gin.Context) {
	c.String(http.StatusOK,"wunai")
})

/*
	curl http://127.0.0.1:8080
	wunai
*/
解析路徑引數

有時候我們需要動態的路由,如/user/:name, 通過呼叫不同的url來傳入不同的Name, /user/:name/*role, *代表可選

	// 匹配/user/youmen
	r.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(http.StatusOK,"Hello %s",name)
	})


/*
		curl http://127.0.0.1:8080/user/youmen
		Hello youmen
*/
獲取Query引數
// 匹配users?name=xxx&role=xxx, role可選
r.GET("/users", func(c *gin.Context) {
  name := c.Query("name")
  role := c.DefaultQuery("role","teacher")
  c.String(http.StatusOK,"%s is a %s",name,role)
})


/*
  curl http://127.0.0.1:8080/users?name=youmen&role=student
  youmen is a student
*/
http常見傳輸格式
/*
    application/json
    application/x-www-form-urlencoded 
    application/xml
    multipart/form-data 
    
    表單引數可以通過PostForm()方法獲取,該方法預設解析的是x-www-form-urlencoded或from-data格式的引數
*/
獲取POST引數
// POST
r.POST("/form", func(c *gin.Context) {
  username := c.PostForm("username")
  password := c.DefaultPostForm("password","123") // 可設定預設值

  c.JSON(http.StatusOK,gin.H{
    "username":username,
    "password":password,
  })
})

/*
		curl http://localhost:8080/form  -X POST -d 'username=youmen&password=1234' 

		{"password":"1234","username":"youmen"}%  
*/

Example2

gin_demo1.go

package main

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

func main() {
	// 建立一個預設的路由引擎
	r := gin.Default()

	// GET:  請求方式: /hello:  請求的路徑
	// 當客戶端以GET的方法請求/hello路徑時,會執行後面的匿名函式
	r.GET("/hello", func(c *gin.Context) {

		// c.JSON:  返回JSON格式的資料
		c.JSON(200, gin.H{
			"message": "Hello World",
		})
	})

	r.POST("/form", func(c *gin.Context) {
		// 表單引數設定預設值
		type1 := c.DefaultPostForm("type","alert")

		// 接受其他的
		username := c.PostForm("username")
		password := c.PostForm("password")

		// 多選框
		hobbys := c.PostFormArray("hobby")
		c.String(http.StatusOK,fmt.Sprintf("type is %s, username is %s, password is %s, habbys is %v",
			type1,username,password,hobbys))
	})
	// 啟動HTTP服務,預設在0.0.0.0:8080啟動服務
	r.Run()
}

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form action="http://127.0.0.1:8080/form" method="post" enctype="application/x-www-form-urlencoded">
        使用者名稱: <input type="text" name="username">
        密碼: <input type="password" name="password">

        <input type="checkbox" value="run" name="hobby"> 跑步
        <input type="checkbox" value="Weightlifting" name="hobby"> 舉重
        <input type="checkbox" value="money" name="hobby"> 金錢

        <input type="submit" value="註冊">
    </form>

</body>
</html>
Query和POST混合引數
	// GET和POST混合
	r.POST("/posts", func(c *gin.Context) {
		id := c.Query("id")
		page := c.DefaultQuery("page", "0")
		username := c.PostForm("username")
		password := c.DefaultPostForm("username", "0000")

		c.JSON(http.StatusOK, gin.H{
			"id":       id,
			"page":     page,
			"username": username,
			"password": password,
		})
	})

/*
		curl "http://localhost:8080/posts?id=9876&page=7"  -X POST -d 'username=geektutu&password=1234'

				{"id":"9876","page":"7","password":"geektutu","username":"geektutu"}%                            
*/
Map引數(字典引數)
// Map引數(字典引數)
r.POST("/post", func(c *gin.Context) {
  ids := c.QueryMap("ids")
  names := c.PostFormMap("names")

  c.JSON(http.StatusOK,gin.H{
    "ids": ids,
    "names": names,
  })
})                       

/*
		curl -g "http://localhost:8080/post?ids[Jack]=001&ids[Tom]=002" -X POST -d 'names[a]=Sam&names[b]=David'
{"ids":{"Jack":"001","Tom":"002"},"names":{"a":"Sam","b":"David"}}%     
*/
重定向(Redirect)
r.GET("/redirect", func(c *gin.Context) {
  c.Redirect(http.StatusMovedPermanently,"/index")
})

r.GET("/index", func(c *gin.Context) {
  c.Request.URL.Path = "/"
  r.HandleContext(c)
})

/*
		curl http://127.0.0.1:8080/redirect -i
		HTTP/1.1 301 Moved Permanently
		Content-Type: text/html; charset=utf-8
		Location: /index
		Date: Tue, 27 Oct 2020 07:40:25 GMT
		Content-Length: 41
*/
分組路由

如果有一組路由,字首都是/api/v1開頭,是否每個路由都需要加上/api/v1這個字首呢?答案是不需要,分組路由可以解決這個問題。利用分組路由還可以更好地實現許可權控制,例如將需要登入鑑權的路由放到同一分組中去,簡化許可權控制。

// group routes 分組路由
defaultHandler := func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"path": c.FullPath(),
	})
}
// group: v1
v1 := r.Group("/v1")
{
	v1.GET("/posts", defaultHandler)
	v1.GET("/series", defaultHandler)
}
// group: v2
v2 := r.Group("/v2")
{
	v2.GET("/posts", defaultHandler)
	v2.GET("/series", defaultHandler)
}


/*
		curl http://localhost:8080/v1/posts
  	{"path":"/v1/posts"}
  	curl http://localhost:8080/v2/posts
  	{"path":"/v2/posts"}
*/

相關文章