类型安全的 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,要做题就需要用到该数据,把数据复制过来感觉又太麻烦,于是就兴 ...
随机推荐
- 理解Promise函数中的resolve和reject
看了promise的用法,一直不明白里面的resolve和reject的用法: 运行了这两段代码之后彻底理解了promise的用法: var p = new Promise(function (res ...
- 动态代理-JDK
代理模式:假设一个场景,你的公司是一位软件公司,你是一位软件工程师,显然客户带着需求不会去找你谈,而是去找商务谈,此时商务就代表公司. 商务的作用:商务可以谈判:也有可能在开发软件之前就谈失败,此时商 ...
- 十、包机制与JavaDoc
一.包机制 为了更好的组织类,Java提供了包机制,用于区别类名的命名空间. 包语句的语句格式为: package pkg1[. pkg2[. pkg3...]]; 一般使用公司域名倒置作为包名:例如 ...
- Python Pandas库 初步使用
用pandas+numpy读取UCI iris数据集中鸢尾花的萼片.花瓣长度数据,进行数据清理,去重,排序,并求出和.累积和.均值.标准差.方差.最大值.最小值
- 小程序 -- 去掉button默认样式
button { position:relative; display:block; margin-left:auto; margin-right:auto; padding-left:14px; p ...
- HbuilderX失焦时自动保存编辑器内容
hbuilderX 有一个非常好用的功能:就是自动保存. 而且不需要安装什么插件,只需要在编辑器设置就可以了.接下来我们一起来设置吧: 1.打开我们的hbuilderX编辑器.在最上排选项栏里打开 & ...
- 2021年3月-第02阶段-前端基础-HTML+CSS阶段-Day03
HTML5 第三天 一. 认识 3D 转换 3D 的特点 近大远小 物体和面遮挡不可见 三维坐标系 x 轴:水平向右 -- 注意:x 轴右边是正值,左边是负值 y 轴:垂直向下 -- 注意:y 轴下面 ...
- Percona停服俄罗斯
2022年3月9日,MySQL重要分支Percona宣布,他们将停止与俄罗斯和白俄罗斯的组织开展新业务,直至另行通知. Percona为支持员工而采取的一些行动如下: 已经在乌克兰目前安全的部分获得了 ...
- python学习-Day16
目录 今日内容详细 内置函数补充 常见内置函数 help() id() int() isinstance() pow() round() sum() 求和 迭代器 可迭代对象 什么是可迭代对象? 哪些 ...
- python学习番外篇——字符串的数据类型转换及内置方法
目录 字符串的数据类型转换及内置方法 类型转换 内置方法 优先掌握的方法 需要掌握的方法 strip, lstrip, rstrip lower, upper, islower, isupper 插入 ...