类型安全的 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,要做题就需要用到该数据,把数据复制过来感觉又太麻烦,于是就兴 ...
 
随机推荐
- PCB产业链、材料、工艺流程详解(1)
			
PCB知识大全 1.什么是pcb,用来干什么? PCB( Printed Circuit Board),中文名称为印制电路板,又称印刷线路板,是重要的电子部件,是电子元器件的支撑体,是电子元器件电气连 ...
 - 【Android开发】监听图库数据库的变化
			
步骤一: 保存图片或者删除之前,初始化ContentObserver ScreenshotContentObserver mScreenObserver = new ScreenshotContent ...
 - 在Android中区分点击和滑动操作
			
转自:http://blog.csdn.net/do168/article/details/51587933 最近在写一个图片浏览安卓应用,想要弄成全屏显示,只在单击时显示工具栏和状态栏,在触摸滑动时 ...
 - git总是需要输入用户名密码问题解决
			
解决办法: git bash进入你的项目目录,输入: git config --global credential.helper store 然后你会在你本地生成一个文本,上边记录你的账号和密码.当然 ...
 - SpringMVC 配置和请求方式
			
SpringMVC 总结内容 一.什么是 Spring MVC ? Spring MVC 是 Spring 对 MVC 思想的实现(三层架构) 优点: 二.前端控制器 Spring MVC 中的前端控 ...
 - JavaScript的使用以及JS常用函数(JS 遍历数组和集合)
			
JavaScript入门 学习总结 1. 什么是 JavaScript 2. JavaScript 的特点 3. JS的使用 编写位置 基本语法 变量 打印变量 数据类型 innerHTML和inne ...
 - vue日历(纯 js,没用任何插件和组件)
			
效果图: 代码: <template> <div class="calender"> <div class="top"> ...
 - conn username/password@servicename
			
conn username/password 方式连接的时候,会碰到这样的错误问题 oracle@prd:/home/oracle/impdir$sqlplus /nolog SQL*Plus: Re ...
 - 修复tunl0-二进制安装calico
			
这篇博文很重要,出现这个问题导致pod之间无法通讯,pod无法连接外网. 出现的问题是二进制方式安装了节点之后, tunl0没有显示,通过ifconfig tunl0 up 启动tunl0 没有意义, ...
 - Jenkins 从小白入门到企业实践打怪放弃之路系列笔记 【持续集成与交付快速入门必备】
			
Jenkins 从小白入门到企业实践打怪放弃之路系列笔记 [持续集成与交付快速入门必备]