前言

对 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. java中如何求出2008年的第1星期星期一是几号?

    题目8: 2008年的第1星期星期一是几号? import java.util.*; public class Test {     public static void main(String[] ...

  2. SpringBoot快速入门(解析+入门案例源码实现)

    这里写目录标题 SpringBoot入门 一.SpringBoot 概念 二.JavaConfig 入门 1. JavaConfig 概念 2. 项目准备 三.常用注解 四.SpringBoot 入门 ...

  3. jdbc连接MySQL数据库+简单实例(普通JDBC方法实现和连接池方式实现)

    jdbc连接数据库 总结内容 1. 基本概念 jdbc的概念 2. 数据库连接 数据库的连接 DAO层思想 重构设计 3. 事务 概念 事务的ACID属性 事务的操作 4. 连接池 为什么要使用连接池 ...

  4. springAop必导jar包

    SpringAop:的底层就是通过JDK动态代理"或"CGLib动态代理为技术目标织入横切逻辑. 做aop:需要导入: spring-aop-4.1.5.RELEASE.jar s ...

  5. php代码审计之——phpstorm动态调试

    xdebug调试 调试环境部署 xdebug的版本需要与PHP版本相对于,所以不要轻易改变PHP环境版本. 0 配置php解析器 1 下载对应版本的xdebug xdebug官网下载地址:https: ...

  6. Java基础之浅谈集合

    Java基础知识.关于List.Set.Map接口的了解,以及ArrayList.LinkedList.HashSet.TreeSet.HashMap.TreeMap...

  7. 聊聊UI自动化的PageObject设计模式

    当我们开发UI自动化测试用例时,需要引用页面中的元素(数据)才能够进行点击(动作)并显示出页面内容.如果我们开发的用例是直接对HTML元素进行操作,则这样的用例无法"应对"页面中U ...

  8. JavaScript基础第05天笔记

    JavaScript基础第05天笔记 1 - 作用域 1.1 作用域概述 通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域.作用域的使用提 ...

  9. mysql学习基础2

    1.什么是SQL? Structured Query Language:结构化查询语言 其实就是定义了操作所有关系型数据库的规则.每一种数据库操作的方式存在不一样的地方,称为"方言" ...

  10. 2021.08.03 P1197 星球大战(并查集)

    2021.08.03 P1197 星球大战(并查集) [P1197 JSOI2008]星球大战 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.可以离线处理.把在线变为离 ...