天天看點

gin源碼解讀3-gin牛逼的context

Gin封裝的最好的地方就是context和對response的處理. github的README的介紹,基本就是對這兩個東西的解釋. 本篇文章主要解釋context的使用方法, 以及其設計原理

在閱讀gin的源碼時, 請求的處理是使用type HandlerFunc func(*Context)來處理的. 也就是

參數是gin.Context, 但是檢視源碼發現其實gin.Context在整個架構處理的地方隻有下面這段:

那為什麼還要利用Context來處理呢. gin的context實作了的context.Context Interface.

經過檢視context.Context相關資料, Context的最佳運用場景就是對Http的處理. 封裝成Conetxt另外的好處就是WithCancel, WithDeadline, WithTimeout, WithValue這些context包衍生的子Context就可以直接來使用.

這個子產品比較簡單, 就是從gin.Context中Set Key-Value, 以及各種個樣的Get方法, 如GetBool, GetString等

實作這些功能也很簡單, 其實就是一個map

這個子產品相當重要了, gin的README基本上都在介紹這個子產品的用法.

gin的标準叫法是Parameters in path. restful風格api如/user/john, 這個路由在gin裡面是/user/:name, 要擷取john就需要使用Param函數

<code>name := context.Param("name")</code>

這個方法實作也很簡單, 就是在tree.go裡面根據路由相關規則解析出來然後指派給gin.Context的Params.

/welcome?firstname=Jane&amp;lastname=Doe這樣一個路由, first, last即是Querystring parameters, 要擷取他們就需要使用Query相關函數.

當然還有其他相關函數:

QueryMap

DefaultQuery 這個預設值的實作更加簡單, 當QueryString中不包含這個值, 直接傳回填入的值

這些方法是的實作是利用net/http的Request的方法實作的

對于檔案相關的操作, 一般生産情況下不建議這樣使用, 因為把檔案上傳到伺服器磁盤, 還得磁盤相關的監控. 我覺得最好利用雲服務商相關的對象存儲, 如:阿裡雲OSS, 七牛雲對象存儲, AWS的對象存儲等來做檔案的相關操作

内置的有json, xml, protobuf, form, query, yaml. 這些Bind極大的減少我們自己去解析各種個樣的資料格式, 提高我們的開發速度

Bind的實作都在gin/binding裡面. 這些内置的Bind都實作了Binding接口, 主要是Bind()函數.

context.BindJSON() 支援MIME為application/json的解析

context.BindXML() 支援MIME為application/xml的解析

context.BindYAML() 支援MIME為application/x-yaml的解析

context.BindQuery() 隻支援QueryString的解析, 和Query()函數一樣

context.BindUri() 隻支援路由變量的解析

Context.Bind() 支援所有的類型的解析, 這個函數盡量還是少用(當QueryString, PostForm, 路由變量在一塊同時使用時會産生意想不到的效果), 目前測試Bind不支援路由變量的解析, Bind()函數的解析比較複雜, 這部分代碼後面再看

Header

GetHeader

這裡的Header是寫到Response裡面的Header. 對于用戶端發的請求的Header可以通過context.Request.Header.Get("Content-Type")擷取

提供對session, cookie的支援

[cookie和session](https://www.cnblogs.com/mayanan/p/15672208.html)

做api常用到的其實就是gin封裝的各種render. 目前支援的有:

func (c *Context) JSON(code int, obj interface{})

func (c *Context) Protobuf(code int, obj interface{})

func (c *Context) YAML(code int, obj interface{}) ...

當然我們可以自定義渲染, 隻要實作func (c *Context) Render(code int, r render.Render)即可.

這裡我們常用的是一個方法是: gin.H{"error": 111}. 這個結構相當實用, 各種render都支援. 其實這個結構很簡單就是type H map[string]interface{}, 當我們要從map轉換各種各樣結構時, 不妨參考gin這裡的代碼

Context說到這裡基本就說完了, 這裡介紹的方法都是開發中特别實用的方法. context的代碼實作也特别有條理, 建議可以看看這部分代碼