首页 > 其他分享 >没想到一个 HTTP Client 居然考虑这么多场景...

没想到一个 HTTP Client 居然考虑这么多场景...

时间:2024-09-14 12:24:50浏览次数:11  
标签:... resty HTTP 请求 err client Client https com


在项目开发过程中,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().
 one rror(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。

标签:...,resty,HTTP,请求,err,client,Client,https,com
From: https://blog.51cto.com/u_15183360/12015796

相关文章

  • 上了高中才发现......
    转载自网易,作者不详。2024年9月14日......
  • FTP、HTTP上传
    1.设置FTP上传打开控制面板—>程序—>启动或关闭windows功能,找到互联网信息服务勾选✔其中的ftp服务器,web管理,万维网服务,系统就会安装IIS服务管理器了,安装过程可能需要等待几分钟。回到电脑桌面,右击“计算机”,点击管理,进入计算机管理界面。在这里,我们就可以看到刚刚添加的II......
  • 减少 try...catch,定义全局统一异常处理器!【送源码】
    前言软件开发springboot项目过程中,不可避免的需要处理各种异常,springmvc架构中各层会出现大量的try{...}catch{...}finally{...}代码块,不仅有大量的冗余代码,而且还影响代码的可读性。这样就需要定义个全局统一异常处理器,以便业务层再也不必处理异常。推荐理由代码......
  • Redis解决"Warning: Using a password with .....may not be safe"
    Redis的命令行工具redis-cli可以连接、访问Redis数据库,在没有设置密码验证的情况下,我们可以无需密码直接访问Redis数据库,如下所示./redis-cli127.0.0.1:6379>127.0.0.1:6379>pingPONG127.0.0.1:6379>我们连接到本地的Redis服务并执行ping命令,该命令用于检测Redis服务是否启动,......
  • 怎么把网站设置成HTTPS访问?
    有很多的网站尤其是公司网站都是可以HTTPS访问的,而且在地址栏前面还会显示安全锁,这就是HTTPS证书所起到的作用。没有安装HTTPS证书的网站强制用HTTPS访问会被浏览器提醒不安全。那么我们怎么解决这个问题呢?解决办法一:首先您要有网站域名的管理权,仅仅是网站的访客是申请不了......
  • Python中的“Try...Except...Finally”:掌握异常处理的艺术
    在编程的世界里,错误与异常就像是旅途中的迷雾,虽然不可避免,但通过正确的导航工具,我们可以安全地穿越。Python作为一种广泛使用的编程语言,提供了丰富的工具来帮助我们处理这些异常情况,其中之一便是“Try...Except...Finally”结构。本文将带你深入了解这一机制的核心概念、实际应用以......
  • 请求HTTP链接的图片等资源被自动变成HTTPS请求的问题解决(顺便可以解决图片防盗链)
    文章目录问题现象问题根本原因常规问题解决办法非Chrome浏览器:控制CSP协议对HTML页面处理nginx配置中处理Chrome浏览器本地处理方式Chrome浏览器通用解决办法(服务器端无法控制新版Chrome这种行为,只能曲线救国--顺便可以解决图片防盗链)网页的网站使用http域名代理服务......
  • HTTP的强制缓存和协商缓存有什么区别和联系?
    你好,我是沐爸,欢迎点赞、收藏、评论和关注。强制缓存和协商缓存是HTTP缓存机制中的两种主要类型,它们在实现方式、工作原理和应用场景上存在显著差异。以下是两者之间的主要区别:一、定义与实现方式强制缓存:定义:强制缓存是一种强制地从本地缓存中读取数据,而不去请求服......
  • Web安全之HTTPS调用详解和证书说明案例示范
    随着互联网的高速发展,网络安全成为了一个不可忽视的话题,特别是在涉及用户敏感信息的业务系统中。在此背景下,使用HTTPS取代HTTP成为了大势所趋。本文将以电商交易系统为例,详细介绍HTTPS的重要性,并探讨如何通过HTTPS来提升网站的安全性。第一章HTTPS的必要性问题:HTTP的不足......
  • 了解 Python中的`try...except...finally`语句块是如何工作的?
    在Python中,try...except...finally语句块是一种异常处理机制,它允许程序优雅地处理运行时错误,确保即使在发生异常的情况下,程序也能执行必要的清理操作,如关闭文件、释放资源等。这种结构不仅提高了程序的健壮性,还使得错误处理更加灵活和可预测。下面,将详细探讨try...except...fin......