2024年您产品必备的10大AI API推荐
没想到一个 HTTP Client 居然考虑这么多场景
在项目开发过程中,HTTP 请求可以说是非常常见的需求,无论是与外部 API 交互,还是实现微服务间的通信。
这篇文章以 Go 语言为背景,探讨 HTTP 客户端的构建。Go 的标准库 net/http 虽然功能强大,但在进行复杂的 HTTP 请求时,往往需要开发者写很多重复代码。
在这种情况下,开发者就需要一个既简单直观又功能强大的 HTTP 客户端库,最终我的调研结果为 go-resty/resty/v2
,让我们看一下这强大的组件。
1. 安装
可以通过以下命令安装:
go get github.com/go-resty/resty/v2
2. 创建一个简单的 HTTP 客户端
通过 resty.New() 来创建一个新的 Resty Client 实例。
package main
import (
"fmt"
"github.com/go-resty/resty/v2"
)
func main() {
// 创建一个新的 Resty 客户端
client := resty.New()
// 发送 GET 请求
resp, err := client.R().Get("https://demo.com/get")
if err != nil {
fmt.Printf("请求失败: %v\n", err)
} else {
fmt.Printf("响应状态码: %d\n", resp.StatusCode())
fmt.Printf("响应正文: %s\n", resp.String())
}
}
3. 常见的 HTTP 请求类型
Resty 提供了简化的 API 来处理不同的 HTTP 请求方法,例如 GET、POST、PUT、PATCH、DELETE 等。
package main
import (
"fmt"
"github.com/go-resty/resty/v2"
)
func main() {
client := resty.New()
// 发送 POST 请求,附带 JSON 数据
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody(`{"username": "test", "password": "1234"}`).
Post("https://demo.com/post")
if err != nil {
fmt.Printf("请求失败: %v\n", err)
} else {
fmt.Printf("响应状态码: %d\n", resp.StatusCode())
fmt.Printf("响应正文: %s\n", resp.String())
}
}
4. 请求参数和 Headers
可以使用 SetQueryParam 和 SetHeader 方法轻松地为请求添加查询参数和请求头。
设置查询参数:
resp, err := client.R().
SetQueryParam("key1", "value1").
SetQueryParam("key2", "value2").
Get("https://demo.com/get")
设置请求头:
resp, err := client.R().
SetHeader("Accept", "application/json").
Get("https://demo.com/get")
5. 发送 JSON 和 XML 数据
支持通过 SetBody 方法发送 JSON 或 XML 格式的数据。可以直接传递结构体、字符串、字节数组等。
发送 JSON 数据:
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody(map[string]string{"username": "test", "password": "1234"}).
Post("https://demo.com/post")
发送 XML 数据:
resp, err := client.R().
SetHeader("Content-Type", "application/xml").
SetBody(`<user><name>test</name><password>1234</password></user>`).
Post("https://demo.com/post")
6. 自动解析 JSON 响应
允许将响应的 JSON 数据自动解析到结构体中,使用 SetResult 或 SetError 方法来处理。
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
client := resty.New()
user := &User{}
resp, err := client.R().
SetResult(user). // 自动解析 JSON 响应到 user 结构体
Get("https://demo.com/users/1")
if err != nil {
fmt.Printf("请求失败: %v\n", err)
} else {
fmt.Printf("用户名: %s\n", user.Name)
fmt.Printf("邮箱: %s\n", user.Email)
}
}
7. 处理表单数据
支持发送 x-www-form-urlencoded 或 multipart/form-data 表单数据。
resp, err := client.R().
SetFormData(map[string]string{
"username": "test",
"password": "1234",
}).
Post("https://demo.com/post")
8. 设置超时
可以通过 SetTimeout 方法为请求设置超时时间。
client := resty.New().
SetTimeout(5 * time.Second) // 请求超时设置为 5 秒
9. 重试机制
内置了重试机制,允许你为失败的请求设置自动重试。
client := resty.New().
SetRetryCount(3). // 重试 3 次
SetRetryWaitTime(2 * time.Second) // 每次重试之间等待 2 秒
SetRetryMaxWaitTime(10 * time.Second) // 最大重试等待时间 10 秒
resp, err := client.R().
AddRetryCondition(
// 如果状态码为 500 则重试
func(r *resty.Response, err error) bool {
return r.StatusCode() == 500
},
).
Get("https://demo.com/status/500")
10. 文件上传与下载
文件上传:
resp, err := client.R().
SetFile("file", "example.txt").
Post("https://demo.com/post")
文件下载:
resp, err := client.R().
SetOutput("output.txt"). // 将响应内容保存到文件
Get("https://demo.com/get")
11. Cookie 管理
支持通过 SetCookie 方法为请求设置 Cookie,也可以通过 SetCookies 方法批量设置多个 Cookie。
设置单个 Cookie:
client.R().
SetCookie(&http.Cookie{
Name: "session_id",
Value: "abc123",
}).
Get("https://demo.com/cookies")
设置多个 Cookie:
client.R().
SetCookies([]*http.Cookie{
{Name: "cookie1", Value: "value1"},
{Name: "cookie2", Value: "value2"},
}).
Get("https://demo.com/cookies")
12. 全局请求设置
允许你通过 client.Set 方法为所有请求设置全局配置。例如,设置所有请求的默认头部或超时时间。
client := resty.New().
SetHeader("Accept", "application/json") // 所有请求都带有 Accept 头
13. 代理支持
支持通过设置代理服务器来发送请求。
client := resty.New().
SetProxy("http://myproxy:8080")
14. 请求与响应日志
内置了请求和响应的日志功能,允许你轻松调试 HTTP 请求。
client := resty.New().
SetDebug(true) // 启用调试模式,打印所有请求和响应细节
15. 自定义 Transport 与 Middleware
允许通过 SetTransport 自定义 HTTP Transport,并支持为每个请求设置自定义的 Middleware。
client := resty.New().
SetTransport(&http.Transport{
Proxy: http.ProxyFromEnvironment,
})
16. 链式调用
支持链式调用,允许你以简洁的方式进行多个设置操作。
client.R().
SetHeader("Accept", "application/json").
SetQueryParam("id", "123").
SetTimeout(5 * time.Second).
Get("https://demo.com/get")
17. 预定义请求(Pre-request Hooks)
允许在实际发送 HTTP 请求之前设置预定义的请求(Pre-request Hook)。
可以使用 OnBeforeRequest 钩子在每个请求发送前执行一些操作,例如修改请求参数、设置头部,或者做一些日志记录。
client := resty.New().
OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
fmt.Println("请求即将发送: ", r.URL)
// 可以在这里动态设置请求头或其他参数
r.SetHeader("Custom-Header", "MyValue")
return nil
})
resp, err := client.R().Get("https://demo.com/get")
18. Post-request Hooks
类似于 OnBeforeRequest。
也支持 OnAfterResponse 钩子,这个钩子允许在请求响应后执行一些操作,比如记录日志、修改响应内容等。
client := resty.New().
OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
fmt.Printf("请求完成,状态码: %d\n", r.StatusCode())
// 可以在这里做一些后处理,例如检查响应内容或记录日志
return nil
})
resp, err := client.R().Get("https://demo.com/get")
19. 多部分表单(Multipart Form)上传
在处理文件上传时,支持通过多部分表单数据发送多个文件或数据段。
可以使用 SetFileReader 或 SetFormData 来上传文件和表单字段。
fileReader, err := os.Open("example.txt")
if err != nil {
log.Fatal(err)
}
defer fileReader.Close()
resp, err := client.R().
SetFileReader("file", "example.txt", fileReader). // 使用文件读取器
SetFormData(map[string]string{
"username": "test",
"password": "1234",
}).
Post("https://demo.com/post")
20. HTTP 代理、认证和 TLS
提供了强大的代理支持、基本认证、Bearer Token 和自定义 TLS 配置等功能。
使用代理:
client.SetProxy("http://proxy-server:8080")
使用认证和 Bearer Token:
client.R().SetBasicAuth("username", "password").Get("https://demo.com/basic-auth/user/passwd")
client.R().SetAuthToken("your-token").Get("https://demo.com/bearer")
自定义 TLS 配置:
client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
21. 上下文(Context 支持)
完全支持 Go 的 context.Context,可以通过 SetContext 来为请求设置上下文,以便在处理超时或取消请求时使用。
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
resp, err := client.R().
SetContext(ctx). // 使用 context 控制请求
Get("https://demo.com/delay/5") // 这个 URL 会延迟 5 秒返回,context 会在 2 秒后超时
22. 自定义错误处理
允许通过 SetError 来指定一个用于处理错误的结构体。
当 HTTP 请求返回非 2xx 的状态码时,可以自动将响应体解析到指定的错误结构体中。
type ErrorResponse struct {
Message string `json:"message"`
}
errResponse := &ErrorResponse{}
resp, err := client.R().
SetError(errResponse). // 自动将错误响应解析为 ErrorResponse
Get("https://demo.com/status/400")
if err != nil {
fmt.Println("请求失败:", errResponse.Message)
}
23. REST API 版本控制
支持通过 SetPathParams 动态控制 URL 中的路径参数,适合用于处理 RESTful API 的版本控制。
resp, err := client.R().
SetPathParams(map[string]string{
"version": "v1",
"id": "1234",
}).
Get("https://api.demo.com/{version}/users/{id}")
24. 多请求并发处理
可以通过 Go 的 goroutine 与 channel 轻松处理并发请求,尤其适合需要同时向多个 API 发起请求的场景。
urls := []string{
"https://demo.com/get?1",
"https://demo.com/get?2",
"https://demo.com/get?3",
}
ch := make(chan *resty.Response)
for _, url := range urls {
go func(url string) {
resp, _ := client.R().Get(url)
ch <- resp
}(url)
}
for range urls {
resp := <-ch
fmt.Println("响应状态码:", resp.StatusCode())
}
25. 全局错误处理器
可以设置全局的错误处理函数,确保每次请求在发生错误时都会调用这个函数。
通过 SetError 可以为每个请求配置错误处理。
client := resty.New().
OnError(func(req *resty.Request, err error) {
fmt.Printf("请求 %s 失败: %v\n", req.URL, err)
})
resp, err := client.R().Get("https://demo.com/status/404")
小结
工作中常用的功能,基本上都包括了…
如果你正在开发需要处理 HTTP 请求的应用,resty 是一个非常值得使用的工具。
在我封装的框架中,HTTP 客户端使用的正是 Resty。
文章转自微信公众号@程序员新亮
- 1. 安装
- 2. 创建一个简单的 HTTP 客户端
- 3. 常见的 HTTP 请求类型
- 4. 请求参数和 Headers
- 5. 发送 JSON 和 XML 数据
- 6. 自动解析 JSON 响应
- 7. 处理表单数据
- 8. 设置超时
- 9. 重试机制
- 10. 文件上传与下载
- 11. Cookie 管理
- 12. 全局请求设置
- 13. 代理支持
- 14. 请求与响应日志
- 15. 自定义 Transport 与 Middleware
- 16. 链式调用
- 17. 预定义请求(Pre-request Hooks)
- 18. Post-request Hooks
- 19. 多部分表单(Multipart Form)上传
- 20. HTTP 代理、认证和 TLS
- 21. 上下文(Context 支持)
- 22. 自定义错误处理
- 23. REST API 版本控制
- 24. 多请求并发处理
- 25. 全局错误处理器
- 小结