基於gin的golang web開發:服務間調用
微服務開發中服務間調用的主流方式有兩種HTTP、RPC,HTTP相對來說比較簡單。本文將使用 Resty
包來實現基於HTTP的微服務調用。
Resty簡介
Resty
是一個簡單的HTTP和REST客戶端工具包,簡單是指使用上非常簡單。Resty在使用簡單的基礎上提供了非常強大的功能,涉及到HTTP客戶端的方方面面,可以滿足我們日常開發使用的大部分需求。
go get安裝
go get github.com/go-resty/resty/v2
使用Resty提交HTTP請求
client := resty.New()
resp, err := client.R().
Get("//httpbin.org/get")
resp, err := client.R().
SetQueryParams(map[string]string{
"page_no": "1",
"limit": "20",
"sort":"name",
"order": "asc",
"random":strconv.FormatInt(time.Now().Unix(), 10),
}).
SetHeader("Accept", "application/json").
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
Get("/search_result")
resp, err := client.R().
SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more").
SetHeader("Accept", "application/json").
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
Get("/show_product")
resp, err := client.R().
SetResult(AuthToken{}).
ForceContentType("application/json").
Get("v2/alpine/manifests/latest")
以上程式碼演示了HTTP GET請求,Resty
提供SetQueryParams
方法設置請求的查詢字元串,使用SetQueryParams
方法我們可以動態的修改請求參數。SetQueryString
也可以設置請求的查詢字元串,如果參數中有變數的話,需要拼接字元串。SetHeader
設置請求的HTTP頭,以上程式碼設置了Accept
屬性。SetAuthToken
設置授權資訊,本質上還是設置HTTP頭,以上例子中HTTP頭會附加Authorization: Bearer BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F
授權屬性。SetResult
設置返回值的類型,Resty自動解析json通過resp.Result().(*AuthToken)
獲取。
下面來看一下POST請求
client := resty.New()
resp, err := client.R().
SetBody(User{Username: "testuser", Password: "testpass"}).
SetResult(&AuthSuccess{}).
SetError(&AuthError{}).
Post("//myapp.com/login")
resp, err := client.R().
SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
SetResult(&AuthSuccess{}).
SetError(&AuthError{}).
Post("//myapp.com/login")
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody(`{"username":"testuser", "password":"testpass"}`).
SetResult(&AuthSuccess{}).
Post("//myapp.com/login")
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody([]byte(`{"username":"testuser", "password":"testpass"}`)).
SetResult(&AuthSuccess{}).
Post("//myapp.com/login")
POST請求的程式碼和GET請求類似,只是最後調用了Post
方法。POST請求可以附帶BODY,程式碼中使用SetBody
方法設置POST BODY。SetBody
參數類型為結構體或map[string]interface{}
時,Resty
自動附加HTTP頭Content-Type: application/json
,當參數為string或[]byte類型時由於很難推斷內容的類型,所以需要手動設置Content-Type
請求頭。SetBody
還支援其他類型的參數,例如上傳文件時可能會用到的io.Reader。SetError
設置HTTP狀態碼為4XX或5XX等錯誤時返回的數據類型。
Resty
也提供了發起其他請求的方法,發起PUT
請求和發起POST
請求程式碼上只需要把最後的Post
改成Put
方法。其他沒有差別,一樣可以調用SetBody
、SetError
等方法。程式碼如下
client := resty.New()
resp, err := client.R().
SetBody(Article{
Title: "go-resty",
Content: "This is my article content, oh ya!",
Author: "Jeevanandam M",
Tags: []string{"article", "sample", "resty"},
}).
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
SetError(&Error{}).
Put("//myapp.com/article/1234")
PATCH,DELETE,HEAD,OPTIONS請求也是一樣的,Resty
為我們提供了一致的方式發起不同請求。
高級應用
代理
使用Resty
作為HTTP客戶端使用的話,添加代理似乎是一個常見的需求。Resty
提供了SetProxy
方法為請求添加代理,還可以調用RemoveProxy
移除代理。程式碼如下:
client := resty.New()
client.SetProxy("//proxyserver:8888")
client.RemoveProxy()
重試
client := resty.New()
client.
SetRetryCount(3).
SetRetryWaitTime(5 * time.Second).
SetRetryMaxWaitTime(20 * time.Second).
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
return 0, errors.New("quota exceeded")
})
client.AddRetryCondition(
func(r *resty.Response) (bool, error) {
return r.StatusCode() == http.StatusTooManyRequests
},
)
由於網路抖動帶來的介面穩定性的問題Resty
提供了重試功能來解決。以上程式碼我們可以看到SetRetryCount
設置重試次數,SetRetryWaitTime
和SetRetryMaxWaitTime
設置等待時間。SetRetryAfter
是一個重試後的回調方法。除此之外還可以調用AddRetryCondition
設置重試的條件。
中間件
Resty
提供了和Gin類似的中間件特性。OnBeforeRequest
和OnAfterResponse
回調方法,可以在請求之前和響應之後加入自定義邏輯。參數包含了resty.Client
和當前請求的resty.Request
對象。成功時返回nil
,失敗時返回error
對象。
client := resty.New()
client.OnBeforeRequest(func(c *resty.Client, req *resty.Request) error {
return nil
})
client.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
return nil
})