Golang Gin 實戰(八)| JSON渲染輸出
- 2020 年 1 月 23 日
- 筆記
現在開發API,所輸出的基本上都是JSON格式的內容,相比比較舊的XML格式,JSON輕便、簡潔、易於傳輸,所以現在的API使用非常多。
Gin對於API JSON的支援非常友好,可以讓我們非常方便的開發一個基於JSON的API。
快速入門
1 2 3 4 5 6 7 |
func main() { r := gin.Default() r.GET("/hello", func(c *gin.Context) { c.JSON(200, gin.H{"message": "hello world"}) }) r.Run(":8080") } |
---|
一個非常簡單的例子,主要知識點在於c.JSON
方法,它可以讓我們非常方便的輸出JSON格式的內容。
現在運行打開瀏覽器訪問http://localhost:8080/hello
可以看到如下內容:
{"message":"hello world"}
這是一個JSON格式的字元串,第三方調用者可以獲得這個JSON內容,把它轉換為一個JSON對象,然後通過message
欄位獲取對應的值,也就是hello world
。
這裡我們使用了gin.H
這個類型來構建了一個鍵值對對象,其實gin.H
是一個map[string]interface{}
。
1 2 |
// H is a shortcut for map[string]interface{} type H map[string]interface{} |
---|
gin.H
主要是為了幫助我們開發者很方便的構建出一個map
對象,不止用於c.JSON
方法,也可以用於其他場景。
Struct 轉 JSON
c.JSON
方法非常強大,不止可以用於map
的輸出,還可以把我們自定義的對象struct
轉為一個json字元串輸出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func main() { r := gin.Default() r.GET("/users/123", func(c *gin.Context) { c.JSON(200, user{ID: 123, Name: "張三", Age: 20}) }) r.Run(":8080") } type user struct { ID int Name string Age int } |
---|
這個例子中我們自定義了一個user
struct 來表示用戶,然後我們註冊一個用戶ID為123的路由,用於輸出這個用戶的資訊,這裡使用的就是user
struct,把它作為參數直接傳給c.JSON
方法即可。
現在我們運行,在瀏覽器里訪問http://localhost:8080/users/123
可以看到如下資訊:
{"ID":123,"Name":"張三","Age":20}
完美、簡單的把這個用戶的資訊作為一個JSON字元串輸出。
自定義JSON欄位名稱
看上面的例子,我們發現輸出的JSON字元串的欄位和我們定義的user
的欄位名一樣,但是這樣的命名格式顯然不太適合JSON,因為JSON的欄位應該是小寫字母開頭的,這比較符合當前大家所遵守的JSON風格。
Gin是支援欄位名字重新命名的,並且很簡單,和Golang原生的JSON一樣。
1 2 3 4 5 |
type user struct { ID int `json:"id"` Name string `json:"name"` Age int `json:"age"` } |
---|
只需要在user
struct 定義的時候為欄位添加json tag
即可。關於 Struct Tag 的內容請參考我以前寫的 Go語言實戰筆記(二十五)| Go Struct Tag 這篇文章,這裡不再贅述。
現在我們重新運行,在瀏覽器里訪問http://localhost:8080/users/123
,發現看到的資訊已經變了:
{"id":123,"name":"張三","age":20}
更符合JSON的風格了,看著更順眼一些。
JSON數組
在一些情況下,比如我們需要獲取所有用戶資訊,那麼表達為JSON字元串來說,就是一個JSON數組。在Gin中,生成JSON數組也很簡單,只要我們傳遞給c.JSON
的參數是個數組就可以。
1 2 3 4 |
allUsers := []user{{ID: 123, Name: "張三", Age: 20}, {ID: 456, Name: "李四", Age: 25}} r.GET("/users", func(c *gin.Context) { c.IndentedJSON(200, allUsers) }) |
---|
我們首先定義了一個user
數組,然後使用c.IndentedJSON
輸出JSON字元串,現在運行打開瀏覽器,訪問http://localhost:8080/users
就可以看到如下資訊,一個JSON數組字元串:
[ { "id": 123, "name": "張三", "age": 20 }, { "id": 456, "name": "李四", "age": 25 } ]
IndentedJSON 美化
上面的例子,我們可以看到,輸出的JSON字元串都是扁平的,沒有縮進,不美觀。對於這種情況,Gin也為我們提供了便捷的方法,讓我們輸出的JSON更好看。
1 2 3 |
r.GET("/users/456", func(c *gin.Context) { c.IndentedJSON(200, user{ID: 456, Name: "李四", Age: 25}) }) |
---|
想美化JSON的輸出,使用c.IndentedJSON
方法即可,現在現在我們運行訪問http://localhost:8080/users/456
就可以看到JSON已經被美化了,更容易看了。。
{ "id": 456, "name": "李四", "age": 25 }
PureJSON
對於JSON字元串中特殊的字元串,比如<
,Gin默認是轉義的,比如變成 u003c
,但是有時候我們為了可讀性,需要保持原來的字元,不進行轉義,這時候我們就可以使用PureJSON
1 2 3 4 5 6 7 8 9 10 11 12 |
r.GET("/json", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "<b>Hello, world!</b>", }) }) r.GET("/pureJson", func(c *gin.Context) { c.PureJSON(200, gin.H{ "message": "<b>Hello, world!</b>", }) }) |
---|
用這兩個API進行對比,我們運行訪問http://localhost:8080/json
,顯示資訊如下:
{"message":"u003cbu003eHello, world!u003c/bu003e"}
特殊字元已經被轉義了,現在訪問http://localhost:8080/pureJson
,顯示的就是原始資訊:
{"message":"<b>Hello, world!</b>"}
可讀性更強。
AsciiJSON
如果要把非Ascii
字元串轉為unicode編碼,Gin同樣提供了非常方便的方法。
1 2 3 |
r.GET("/asciiJSON", func(c *gin.Context) { c.AsciiJSON(200, gin.H{"message": "hello 飛雪無情"}) }) |
---|
通過c.AsciiJSON
方法,Gin可以把所有的非Ascii
字元全部轉義為unicode
編碼,現在我們運行看看結果。
{"message":"hello u98deu96eau65e0u60c5"}
飛雪無情
4個字已經被轉義為u98deu96eau65e0u60c5
了,避免亂碼。
加速JSON
在Gin中,提供了兩種JSON解析器,用於生成JSON字元串。默認的是Golang(Go語言)內置的JSON,當然你也可以使用jsoniter,據說速度很快。如果要使用jsoniter,我們在go build
編譯的時候只需要這麼做即可:
go build -tags=jsoniter .
這樣我們就是用了jsoniter,是基於條件編譯的技術,具體可以參考我這篇文章 Go語言中自動選擇json解析庫 。
精彩文章推薦
Golang Gin 實戰(六)| 獲取Form表單參數和原理分析
Golang Gin 實戰(四)| URL查詢參數的獲取和原理分析
Golang Gin 實戰(二)| 簡便的Restful API 實現