简介
resty
是 Go 语言的一个 HTTP client 库。resty
功能强大,特性丰富。它支持几乎所有的 HTTP 方法(GET/POST/PUT/DELETE/OPTION/HEAD/PATCH等),并提供了简单易用的 API。
快速使用
本文代码使用 Go Modules。
创建目录并初始化:
1 | cmd复制代码$ mkdir resty && cd resty |
安装resty
库:
1 | cmd复制代码$ go get -u github.com/go-resty/resty/v2 |
下面我们来获取百度首页信息:
1 | golang复制代码package main |
resty
使用比较简单。
- 首先,调用一个
resty.New()
创建一个client
对象; - 调用
client
对象的R()
方法创建一个请求对象; - 调用请求对象的
Get()/Post()
等方法,传入参数 URL,就可以向对应的 URL 发送 HTTP 请求了。返回一个响应对象; - 响应对象提供很多方法可以检查响应的状态,首部,Cookie 等信息。
上面程序中我们获取了:
StatusCode()
:状态码,如 200;Status()
:状态码和状态信息,如 200 OK;Proto()
:协议,如 HTTP/1.1;Time()
:从发送请求到收到响应的时间;ReceivedAt()
:接收到响应的时刻;Size()
:响应大小;Header()
:响应首部信息,以http.Header
类型返回,即map[string][]string
;Cookies()
:服务器通过Set-Cookie
首部设置的 cookie 信息。
运行程序输出的响应基本信息:
1 | golang复制代码Response Info: |
首部信息:
1 | golang复制代码Headers: |
注意其中有一个Set-Cookie
首部,这部分内容会出现在 Cookie 部分:
1 | golang复制代码Cookies: |
自动 Unmarshal
现在很多网站提供 API 接口,返回结构化的数据,如 JSON/XML 格式等。resty
可以自动将响应数据 Unmarshal 到对应的结构体对象中。下面看一个例子,我们知道很多 js 文件都托管在 cdn 上,我们可以通过api.cdnjs.com/libraries
获取这些库的基本信息,返回一个 JSON 数据,格式如下:
接下来,我们定义结构,然后使用resty
拉取信息,自动 Unmarshal:
1 | golang复制代码type Library struct { |
可以看到,我们只需要创建一个结果类型的对象,然后调用请求对象的SetResult()
方法,resty
会自动将响应的数据 Unmarshal 到传入的对象中。这里设置请求信息时使用链式调用的方式,即在一行中完成多个设置。
运行:
1 | golang复制代码$ go run main.go |
一共 4040 个库,第一个就是 Vue✌️。我们请求https://api.cdnjs.com/libraries/vue
就能获取 Vue 的详细信息:
感兴趣可自行用resty
来拉取这些信息。
一般请求下,resty
会根据响应中的Content-Type
来推断数据格式。但是有时候响应中无Content-Type
首部或与内容格式不一致,我们可以通过调用请求对象的ForceContentType()
强制让resty
按照特定的格式来解析响应:
1 | golang复制代码client.R(). |
请求信息
resty
提供了丰富的设置请求信息的方法。我们可以通过两种方式设置查询字符串。一种是调用请求对象的SetQueryString()
设置我们拼接好的查询字符串:
1 | golang复制代码client.R(). |
另一种是调用请求对象的SetQueryParams()
,传入map[string]string
,由resty
来帮我们拼接。显然这种更为方便:
1 | golang复制代码client.R(). |
resty
还提供一种非常实用的设置路径参数接口,我们调用SetPathParams()
传入map[string]string
参数,然后后面的 URL 路径中就可以使用这个map
中的键了:
1 | golang复制代码client.R(). |
注意,路径中的键需要用{}
包起来。
设置首部:
1 | golang复制代码client.R(). |
设置请求消息体:
1 | golang复制代码client.R(). |
消息体可以是多种类型:字符串,[]byte
,对象,map[string]interface{}
等。
设置携带Content-Length
首部,resty
自动计算:
1 | golang复制代码client.R(). |
有些网站需要先获取 token,然后才能访问它的 API。设置 token:
1 | golang复制代码client.R(). |
案例
最后,我们通过一个案例来将上面介绍的这些串起来。现在我们想通过 GitHub 提供的 API 获取组织的仓库信息,API 文档见文后链接。GitHub API 请求地址为https://api.github.com
,获取仓库信息的请求格式如下:
1 | golang复制代码GET /orgs/{org}/repos |
我们还可以设置以下这些参数:
accept
:首部,这个必填,需要设置为application/vnd.github.v3+json
;org
:组织名,路径参数;type
:仓库类型,查询参数,例如public/private/forks(fork的仓库)
等;sort
:仓库的排序规则,查询参数,例如created/updated/pushed/full_name
等。默认按创建时间排序;direction
:升序asc
或降序dsc
,查询参数;per_page
:每页多少条目,最大 100,默认 30,查询参数;page
:当前请求第几页,与per_page
一起做分页管理,默认 1,查询参数。
GitHub API 必须设置 token 才能访问。登录 GitHub 账号,点开右上角头像,选择Settings
:
然后,选择Developer settings
:
选择Personal access tokens
,然后点击右上角的Generate new token
:
填写 Note,表示 token 的用途,这个根据自己情况填写即可。下面复选框用于选择该 token 有哪些权限,这里不需要勾选:
点击下面的Generate token
按钮即可生成 token:
注意,这个 token 只有现在能看见,关掉页面下次再进入就无法看到了。所以要保存好,另外不要用我的 token,测试完程序后我会删除 token😭。
响应中的 JSON 格式数据如下所示:
字段非常多,为了方便起见,我这里之处理几个字段:
1 | golang复制代码type Repository struct { |
然后使用resty
设置路径参数,查询参数,首部,Token 等信息,然后发起请求:
1 | golang复制代码func main() { |
上面程序拉取以创建时间升序排列的 3 个仓库:
1 | golang复制代码$ go run main.go |
Trace
介绍完resty
的主要功能之后,我们再来看看resty
提供的一个辅助功能:trace。我们在请求对象上调用EnableTrace()
方法启用 trace。启用 trace 可以记录请求的每一步的耗时和其他信息。resty
支持链式调用,也就是说我们可以在一行中完成创建请求,启用 trace,发起请求:
1 | golang复制代码client.R().EnableTrace().Get("https://baidu.com") |
在完成请求之后,我们通过调用请求对象的TraceInfo()
方法获取信息:
1 | golang复制代码ti := resp.Request.TraceInfo() |
我们可以获取以下信息:
DNSLookup
:DNS 查询时间,如果提供的是一个域名而非 IP,就需要向 DNS 系统查询对应 IP 才能进行后续操作;ConnTime
:获取一个连接的耗时,可能从连接池获取,也可能新建;TCPConnTime
:TCP 连接耗时,从 DNS 查询结束到 TCP 连接建立;TLSHandshake
:TLS 握手耗时;ServerTime
:服务器处理耗时,计算从连接建立到客户端收到第一个字节的时间间隔;ResponseTime
:响应耗时,从接收到第一个响应字节,到接收到完整响应之间的时间间隔;TotalTime
:整个流程的耗时;IsConnReused
:TCP 连接是否复用了;IsConnWasIdle
:连接是否是从空闲的连接池获取的;ConnIdleTime
:连接空闲时间;RequestAttempt
:请求执行流程中的请求次数,包括重试次数;RemoteAddr
:远程的服务地址,IP:PORT
格式。
resty
对这些区分得很细。实际上resty
也是使用标准库net/http/httptrace
提供的功能,httptrace
提供一个结构,我们可以设置各个阶段的回调函数:
1 | golang复制代码// src/net/http/httptrace.go |
可以从字段名简单了解回调的含义。resty
在启用 trace 后设置了如下回调:
1 | golang复制代码// src/github.com/go-resty/resty/trace.go |
然后在获取TraceInfo
时,根据各个时间点计算耗时:
1 | golang复制代码// src/github.com/go-resty/resty/request.go |
运行输出:
1 | golang复制代码$ go run main.go |
我们看到 TLS 消耗了近一半的时间。
总结
本文我介绍了 Go 语言一款非常方便易用的 HTTP Client 库。 resty
提供非常实用的,丰富的 API。链式调用,自动 Unmarshal,请求参数/路径设置这些功能非常方便好用,让我们的工作事半功倍。限于篇幅原因,很多高级特性未能一一介绍,如提交表单,上传文件等等等等。只能留待感兴趣的大家去探索了。
大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue😄
参考
- Go 每日一库 GitHub:github.com/darjun/go-d…
- resty GitHub:github.com/go-resty/re…
- GitHub API:docs.github.com/en/rest/ove…
我
我的博客:darjun.github.io
欢迎关注我的微信公众号【GoUpUp】,共同学习,一起进步~
本文转载自: 掘金