前言

对 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-zerohttpc 包是怎么使用并保证类型安全的。

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 就可以做到类型安全,并且代码非常精简。支持了如我们代码所示的 pathformheaderjson,可以非常方便且类型安全的发送 HTTP 请求。

更多能力

除了上面展示的简单易用和类型安全以外,httpc 包还有以下特点:

  1. context 的超时控制
  2. OpenTelemetry 自动集成,服务端返回的 trace-id, span-id 都会自动被记录到日志里,便于后续客户端、服务端协同查问题
  3. 可以通过 httpc.Service 来获得熔断能力,当服务端有问题,会自动熔断隔离请求,避免浪费时间等待和加剧服务端压力

项目地址

https://github.com/zeromicro/go-zero

欢迎使用 go-zerostar 支持我们!

微信交流群

关注『微服务实践』公众号并点击 交流群 获取社区群二维码。

如果你有 go-zero 的使用心得文章,或者源码学习笔记,欢迎通过公众号联系投稿!

类型安全的 Go HTTP 请求的更多相关文章

  1. Android okHttp网络请求之Retrofit+Okhttp+RxJava组合

    前言: 通过上面的学习,我们不难发现单纯使用okHttp来作为网络库还是多多少少有那么一点点不太方便,而且还需自己来管理接口,对于接口的使用的是哪种请求方式也不能一目了然,出于这个目的接下来学习一下R ...

  2. 依赖注入及AOP简述(六)——字符串请求模式 .

    2.     依赖注入对象的请求模式 前一节我们讨论了关于声明注入点的几种方法,这一节主要来介绍在注入点上如何定位到所需要的标识符的话题.基本上,我们可以用字符串为标识符来请求依赖对象.或者用全类名( ...

  3. Retrofit网络请求库应用01

    PS:什么是Retrofit? 在官方文档中有这样一句话--A type-safe HTTP client for Android and Java(一个类型安全的http client库),具体的话 ...

  4. 自动类型安全的.NET标准REST库refit

    在SCOTT HANSELMAN 博客上看到一个好东西<Exploring refit, an automatic type-safe REST library for .NET Standar ...

  5. Effective Java 第三版——33. 优先考虑类型安全的异构容器

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  6. Android网络请求框架之Retrofit实践

    网络访问框架经过了从使用最原始的AsyncTask构建简单的网络访问框架(甚至不能称为框架),后来使用开源的android-async-http库,再到使用google发布的volley库,一直不懈的 ...

  7. Xamarin Forms Api请求开源框架Refit

    用于.NET Core,Xamarin和.NET的自动类型安全的REST库,Refit是一个受Square Square Retrofit库影响的库,但它比REST API更容易: public in ...

  8. 使用Retrofit2+RxJava2+ProtoBuf实现网络请求

    引言 Retrofit 是一个用于 Android 和 Java 平台的类型安全的,底层使用OkHttp实现网络请求框架.Retrofit 通过将 API 抽象成 Java 接口而让我们连接到 RES ...

  9. go语言带cookie的net客户端请求与[]byte转string

    前些日子参加了一个叫Advent of Code的编程大赛,每天一道题,快活似神仙.这每道题都有自己的拼图数据输入puzzle input,要做题就需要用到该数据,把数据复制过来感觉又太麻烦,于是就兴 ...

随机推荐

  1. 顺利通过EMC实验(19)

  2. testview属性之详解

    安卓开发当中TextView是最常用的组件之一了,那么现在就来详细的了解下TextView的属性: Android:autoLink设置是否当文本为URL链接/email/电话号码/map时,文本显示 ...

  3. 前端每日实战:133# 视频演示如何用 CSS 和 GSAP 创作有多个关键帧的连续动画

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/eLMKJG 可交互视频 此视频是可 ...

  4. Canvas 制作海报

      HTML <template> <view class="content"> <view class="flex_row_c_c mod ...

  5. java中接口interface有什么用呢?举例!

    接口只有方法的定义,没有方法的任何实现.那这有什么意义呢?马克-to-win: 接口就像一个服务合同.接口只关心必须得干什么而不关心如何去实现它.有 意义吗?有意义.马克-to-win:比如我们的软件 ...

  6. java中“类”和“对象”到底有什么联系

    4.object和Class配合工作原理    [新手可忽略不影响继续学习] Class是"类"的意思,是抽象的,并没有具体的说是哪个东西.而object是具体的,实实在在存在的一 ...

  7. 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版本然后 ...

  8. Python入门-深入了解数据类型以及方法

    写在开始:每一种数据类型,有对应一种功能,面对不同的问题,使用不同类型. 1.全部数据类型 1.2数值型:解决数字的计算问题 #基础的计算,求除结果,求商,求余数 print(10 / 3) prin ...

  9. 『现学现忘』Git基础 — 1、版本控制系统介绍

    在具体了解Git之前,首先需要我们了解一下VCS,即版本控制系统(version control system) 1.什么是版本控制系统 版本控制是一种记录一个或若干个文件内容变化,以便将来查阅特定版 ...

  10. 使用java生成备份sqlserver数据表的insert语句

    针对sqlserver数据表的备份工具很多,有时候条件限制需要我们自己生成insert语句,以便后期直接执行这些插入语句.下面提供了一个简单的思路,针对mysql或oracle有兴趣的以后可以试着修改 ...