对于Gophers来说,我们基本上是为客户编写请求代码。有时我们需要请求第三方提供的RESTful API。这时,我们会感到组装请求很困难,不是难以实现,而是容易出错。
例如,如果我们想要发送如下请求,看起来很简单,但实际编写起来仍然很繁琐。
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.
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://go-zero.dev/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
了。
通过定义请求类型并使用Do
发送请求,httpc
实现非常易于理解。我们的代码支持path
、form
、header
和json
,非常容易和类型安全地发送HTTP
请求。
更多功能
除了上述易用性和类型安全性之外,httpc
包还具有以下功能。
- 使用
context
控制超时。你可以为请求传递ctx
。 - 自动集成
OpenTelemetry
。服务器返回的trace-id
和span-id
将自动写入日志,以便客户端和服务器共同解决问题。 - 使用
httpc.Service
获取断路器功能。当服务器端出现问题时,它将自动停止发送请求,以避免无用的请求并减轻服务器端的压力。``` Want to Connect?You're welcome to use go-zero and star to support us!
评论(0)