型別安全的 Go HTTP 請求
前言
對 Gopher 來說,雖然我們基本都是在寫程式碼讓別人來請求,但是有時候,我們也需要去請求第三方提供的 RESTful 介面,這個時候,我們才能感受到前端同學拼接 HTTP 請求引數的痛苦。
比如,我們要發起類似這樣一個請求,看起來很簡單,實際寫起來還是比較繁瑣的。
POST /articles/5/update?device=ios HTTP/1.1 Host: go-zero.dev Authorization: Bearer <jwt-token> {"author":"kevin","body":"this is not important!","title":"my title","type":6}
Go 原生寫法
這個 API 其實是蠻簡單的,我們直接上手就可以寫出來。
func main() { var buf bytes.Buffer encoder := json.NewEncoder(&buf) params := map[string]interface{}{ "title": "my title", "body": "this is not important!", "author": "kevin", "type": 6, } if err := encoder.Encode(params); err != nil { fmt.Fprintln(os.Stderr, err) return } url := fmt.Sprintf("http://localhost:3333/articles/%d/update?device=%s", 5, "ios") req, err := http.NewRequest(http.MethodPost, url, &buf) if err != nil { fmt.Fprintln(os.Stderr, err) return } req.Header.Add("Authorization", "Bearer <jwt-token>") cli := http.Client{} resp, err := cli.Do(req) if err != nil { fmt.Fprintln(os.Stderr, err) return } io.Copy(os.Stdout, resp.Body) }
我們跑了測試一下,發現沒有得到 200 OK
,抓包看一下,請求如下。各位不要往下看,你能想到失敗的原因嗎?
POST /articles/5/update?device=ios HTTP/1.1 Host: go-zero.dev User-Agent: Go-http-client/1.1 Content-Length: 79 Authorization: Bearer <jwt-token> Accept-Encoding: gzip {"author":"kevin","body":"this is not important!","title":"my title","type":6}
具體失敗原因這裡就不細講了,我們先來分析這段程式碼。可以看到其中為了拼接引數使用了 map[string]interface{}
,對於其中每個欄位我們是不能校驗型別是否匹配的,只有傳送出去了,收到了服務端的 200 OK
,我們才能確認傳對了。比如其中的 type
引數,這裡是使用了 int
型別,我們可能順手寫成 string
型別,但是不請求我們還是很難發現這個引數寫錯了的。
那麼讓我們看看 go-zero
裡 httpc
包是怎麼使用並保證型別安全的。
httpc
實現
我們看看用 httpc
包來請求的程式碼怎麼寫。
const url = "http://go-zero.dev/articles/:id/update" type UpdateArticle struct { ID int `path:"id"` Device string `form:"device,options=ios,android,web,desktop"` Authorization string `header:"Authorization"` Title string `json:"title"` Body string `json:"body"` Author string `json:"author"` Type int `json:"type"` } func main() { data := &UpdateArticle{ ID: 5, Device: "ios", Authorization: "Bearer <jwt-token>", Title: "my title", Body: "this is not important!", Author: "kevin", Type: 6, } resp, err := httpc.Do(context.Background(), http.MethodPost, url, data) if err != nil { fmt.Fprintln(os.Stderr, err) return } io.Copy(os.Stdout, resp.Body) }
寫完測試一下,結果正如預期:
POST /articles/5/update?device=ios HTTP/1.1 Host: go-zero.dev User-Agent: Go-http-client/1.1 Content-Length: 79 Content-Type: application/json; charset=utf-8 Authorization: Bearer <jwt-token> Accept-Encoding: gzip {"author":"kevin","body":"this is not important!","title":"my title","type":6}
你發現了沒有,跟前面的對比,其中多了 Content-Type: application/json; charset=utf-8
,而我們之前寫法裡忘記設定 Content-Type
了。
而 httpc
的寫法只要定義好請求的型別,然後通過 httpc.Do
就可以做到型別安全,並且程式碼非常精簡。支援瞭如我們程式碼所示的 path
、 form
、 header
和 json
,可以非常方便且型別安全的傳送 HTTP
請求。
更多能力
除了上面展示的簡單易用和型別安全以外, httpc
包還有以下特點:
-
context
的超時控制 -
OpenTelemetry
自動整合,服務端返回的trace-id
,span-id
都會自動被記錄到日誌裡,便於後續客戶端、服務端協同查問題 -
可以通過
httpc.Service
來獲得熔斷能力,當服務端有問題,會自動熔斷隔離請求,避免浪費時間等待和加劇服務端壓力
專案地址
https://github.com/zeromicro/go-zero
歡迎使用 go-zero
並 star
支援我們!
微信交流群
關注『 微服務實踐 』公眾號並點選 交流群 獲取社群群二維碼。
如果你有 go-zero
的使用心得文章,或者原始碼學習筆記,歡迎通過公眾號聯絡投稿!
- 【演算法篇】刷了兩道大廠面試題,含淚 ”重學陣列“
- 2022 開源軟體安全狀況報告:超 41% 的企業對開源安全沒有足夠的信心
- JavaScript中async和await的使用以及佇列問題
- Flex & Bison 開始
- Obsidian基礎教程
- 分享自己平時使用的socket多客戶端通訊的程式碼技術點和軟體使用
- iNeuOS工業網際網路作業系統,增加2154個檢視建模(WEB組態)行業向量圖元、大屏背景及相關圖元
- 多臺雲伺服器的 Kubernetes 叢集搭建
- Elasticsearch學習系列四(聚合搜尋)
- 關於swiper外掛在vue2的使用
- 使用 Abp.Zero 搭建第三方登入模組(一):原理篇
- LVGL庫入門教程 - 顏色和影象
- Node.js精進(4)——事件觸發器
- 物聯網?快來看 Arduino 上雲啦
- SpringBoot JWT Redis 開源知識社群系統
- CVPR2022 | 可精簡域適應
- Spring框架系列(3) - 深入淺出Spring核心之控制反轉(IOC)
- 面試突擊59:一個表中可以有多個自增列嗎?
- CVPR2022 | 弱監督多標籤分類中的損失問題
- JDBC、ORM、JPA、Spring Data JPA,傻傻分不清楚?一文帶你釐清箇中曲直,給你個選擇SpringDataJPA的...