类型安全的 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
的使用心得文章,或者源码学习笔记,欢迎通过公众号联系投稿!
类型安全的 Go HTTP 请求的更多相关文章
- Android okHttp网络请求之Retrofit+Okhttp+RxJava组合
前言: 通过上面的学习,我们不难发现单纯使用okHttp来作为网络库还是多多少少有那么一点点不太方便,而且还需自己来管理接口,对于接口的使用的是哪种请求方式也不能一目了然,出于这个目的接下来学习一下R ...
- 依赖注入及AOP简述(六)——字符串请求模式 .
2. 依赖注入对象的请求模式 前一节我们讨论了关于声明注入点的几种方法,这一节主要来介绍在注入点上如何定位到所需要的标识符的话题.基本上,我们可以用字符串为标识符来请求依赖对象.或者用全类名( ...
- Retrofit网络请求库应用01
PS:什么是Retrofit? 在官方文档中有这样一句话--A type-safe HTTP client for Android and Java(一个类型安全的http client库),具体的话 ...
- 自动类型安全的.NET标准REST库refit
在SCOTT HANSELMAN 博客上看到一个好东西<Exploring refit, an automatic type-safe REST library for .NET Standar ...
- Effective Java 第三版——33. 优先考虑类型安全的异构容器
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Android网络请求框架之Retrofit实践
网络访问框架经过了从使用最原始的AsyncTask构建简单的网络访问框架(甚至不能称为框架),后来使用开源的android-async-http库,再到使用google发布的volley库,一直不懈的 ...
- Xamarin Forms Api请求开源框架Refit
用于.NET Core,Xamarin和.NET的自动类型安全的REST库,Refit是一个受Square Square Retrofit库影响的库,但它比REST API更容易: public in ...
- 使用Retrofit2+RxJava2+ProtoBuf实现网络请求
引言 Retrofit 是一个用于 Android 和 Java 平台的类型安全的,底层使用OkHttp实现网络请求框架.Retrofit 通过将 API 抽象成 Java 接口而让我们连接到 RES ...
- go语言带cookie的net客户端请求与[]byte转string
前些日子参加了一个叫Advent of Code的编程大赛,每天一道题,快活似神仙.这每道题都有自己的拼图数据输入puzzle input,要做题就需要用到该数据,把数据复制过来感觉又太麻烦,于是就兴 ...
随机推荐
- 顺利通过EMC实验(19)
- testview属性之详解
安卓开发当中TextView是最常用的组件之一了,那么现在就来详细的了解下TextView的属性: Android:autoLink设置是否当文本为URL链接/email/电话号码/map时,文本显示 ...
- 前端每日实战:133# 视频演示如何用 CSS 和 GSAP 创作有多个关键帧的连续动画
效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/eLMKJG 可交互视频 此视频是可 ...
- Canvas 制作海报
HTML <template> <view class="content"> <view class="flex_row_c_c mod ...
- java中接口interface有什么用呢?举例!
接口只有方法的定义,没有方法的任何实现.那这有什么意义呢?马克-to-win: 接口就像一个服务合同.接口只关心必须得干什么而不关心如何去实现它.有 意义吗?有意义.马克-to-win:比如我们的软件 ...
- java中“类”和“对象”到底有什么联系
4.object和Class配合工作原理 [新手可忽略不影响继续学习] Class是"类"的意思,是抽象的,并没有具体的说是哪个东西.而object是具体的,实实在在存在的一 ...
- Visual Studio 2022 git error Unable to negotiate with xx.xxx.xxxx port 22: no matching host key type found. Their offer: ssh-rsa
前言 前两天因为升级了Git导致git提交拉取的时候都提示下面这个异常,然后经过一番折腾以后终于把这个问题解决了.但是今天我升级了下Visual Studio 2022将其升级到了17.1.3版本然后 ...
- Python入门-深入了解数据类型以及方法
写在开始:每一种数据类型,有对应一种功能,面对不同的问题,使用不同类型. 1.全部数据类型 1.2数值型:解决数字的计算问题 #基础的计算,求除结果,求商,求余数 print(10 / 3) prin ...
- 『现学现忘』Git基础 — 1、版本控制系统介绍
在具体了解Git之前,首先需要我们了解一下VCS,即版本控制系统(version control system) 1.什么是版本控制系统 版本控制是一种记录一个或若干个文件内容变化,以便将来查阅特定版 ...
- 使用java生成备份sqlserver数据表的insert语句
针对sqlserver数据表的备份工具很多,有时候条件限制需要我们自己生成insert语句,以便后期直接执行这些插入语句.下面提供了一个简单的思路,针对mysql或oracle有兴趣的以后可以试着修改 ...