介绍: #
RESTful API 已成为现代 Web 开发的基石,可实现客户端与服务器之间的无缝通信。在本文中,我们将探索使用 Resty(一种流行的 HTTP 客户端库)在 Go 中执行常见操作(如 GET、POST、UPDATE 和 DELETE 请求)的强大功能和简便性。我们还将学习如何在请求中传递标头,从而使我们能够自定义和增强 API 交互。
网址:https://github.com/go-resty/resty
安装 Resty: #
首先,我们需要在 Go 环境中安装 Resty。我们可以使用以下命令来安装 Resty 包:
go get -u github.com/go-resty/resty/v2
GET #
发出 GET 请求: #
让我们首先研究如何使用 Resty v2 执行 GET 请求。以下代码片段演示了一个简单的 GET 请求并将响应绑定到结构体中:
package main
import (
"fmt"
"log"
"github.com/go-resty/resty/v2"
)
type DevUser struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
var users []DevUser
response, err := resty.New().R().SetResult(&users).Get("https://api.example.com/users")
if err != nil {
log.Fatal(err)
}
fmt.Println("GET Response:", response.Status())
fmt.Printf("Retrieved %d users:\n", len(users))
for _, user := range users {
fmt.Printf("User ID: %d, Name: %s, Email: %s\n", user.ID, user.Name, user.Email)
}
}
复杂点的GET请求 #
// 创建Resty客户端
client := resty.New()
// 设置查询参数
resp, err := client.R().
SetQueryParams(map[string]string{
"page_no": "1",
"limit": "20",
"sort":"name",
"order": "asc",
"random":strconv.FormatInt(time.Now().Unix(), 10),
}).
SetHeader("Accept", "application/json").
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
Get("/search_result")
// 使用Request.SetQueryString方法的示例
resp, err := client.R().
SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more").
SetHeader("Accept", "application/json").
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
Get("/show_product")
// 如果需要,可以强制指定响应内容类型告诉Resty将JSON响应解析为你的结构体
resp, err := client.R().
SetResult(result).
ForceContentType("application/json").
Get("v2/alpine/manifests/latest")
POST #
发出 POST 请求: #
要使用 Resty v2 执行 POST 请求并将响应绑定到结构体中,我们可以使用 .SetResult() 方法。下面的示例说明了如何发送带有 JSON 有效负载的 POST 请求并将响应绑定到结构体中:
package main
import (
"fmt"
"log"
"github.com/go-resty/resty/v2"
)
type DevUser struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
var createdUser DevUser
payload := DevUser{
Name: "John Doe",
Email: "johndoe@example.com",
}
response, err := resty.New().R().
SetHeader("Content-Type", "application/json").
SetBody(&payload).
SetResult(&createdUser).
Post("https://api.example.com/users")
if err != nil {
log.Fatal(err)
}
fmt.Println("POST Response:", response.Status())
fmt.Printf("Created User: ID: %d, Name: %s, Email: %s\n", createdUser.ID, createdUser.Name, createdUser.Email)
}
实例处理流数据 #
func Test_pedestrian2(t *testing.T) {
client := resty.New()
// 设置文件路径
values := make(url.Values)
values["files"] = []string{"E:\\镜像测试\\live.MP4"}
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetHeader("model", "yolo-v8-person").
SetFormDataFromValues(values).
SetFormData(map[string]string{
"mode": "intervalFrame",
"startTime": "2448000",
"endTime": "5648000",
"intervalSeconds": "1000",
"diff": "2.5",
}).
SetDoNotParseResponse(true).
Post("http://127.0.0.1:9120/api/v1/detection/video")
if err != nil {
t.Fatalf("Request failed: %v", err)
}
defer resp.RawBody().Close()
decoder := json.NewDecoder(resp.RawBody())
result := new(param.DetectionResult)
for {
// 按照 JSON 对象进行解码
if err := decoder.Decode(result); err != nil {
if err.Error() == "EOF" {
break // 读取完毕
}
fmt.Println("Decode error:", err)
break
}
// 处理解析结果
fmt.Println(result.File, " ", result.StartTime, " ", result.EndTime)
}
//scanner := bufio.NewScanner(resp.RawBody())
//for scanner.Scan() {
// // 逐行读取
// line := scanner.Text() // 获取当前行的文本
// fmt.Println("Received line:", line)
//}
// 逐块读取响应内容
//buf := make([]byte, 1024)
//for {
// n, err := resp.RawBody().Read(buf)
// if n > 0 {
// fmt.Println(string(buf[:n])) // 输出读取到的内容
// }
// if err != nil {
// if err.Error() != "EOF" {
// fmt.Println("Read error:", err)
// }
// break
// }
//}
}
if resp.StatusCode() != http.StatusOK {
err = fmt.Errorf("Unexpected status code: %d, status: %s\n", resp.StatusCode(),resp.Status())
return
}
type result struct {
Data []param.OcrResult `json:"data"`
Err string `json:"err"`
}
data := new(result)
err = json.Unmarshal(resp.Body(), data)
if err != nil {
fmt.Println("json unmarshal err:", err)
common.Log.Error()
return
}
多种POST请求示例 #
// 创建Resty客户端
client := resty.New()
// POST JSON字符串
// 如果已经设置了客户端级别的设置,则无需设置内容类型
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody(`{"username":"testuser", "password":"testpass"}`).
SetResult(&AuthSuccess{}). // 或者 SetResult(AuthSuccess{}).
Post("https://myapp.com/login")
// POST []byte字节数组
// 如果已经设置了客户端级别的设置,则无需设置内容类型
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody([]byte(`{"username":"testuser", "password":"testpass"}`)).
SetResult(&AuthSuccess{}). // 或者 SetResult(AuthSuccess{}).
Post("https://myapp.com/login")
// POST结构体,默认是JSON内容类型,无需设置
resp, err := client.R().
SetBody(User{Username: "testuser", Password: "testpass"}).
SetResult(&AuthSuccess{}). // 或者 SetResult(AuthSuccess{}).
SetError(&AuthError{}). // 或者 SetError(AuthError{}).
Post("https://myapp.com/login")
// POST Map,默认是JSON内容类型,无需设置
resp, err := client.R().
SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
SetResult(&AuthSuccess{}). // 或者 SetResult(AuthSuccess{}).
SetError(&AuthError{}). // 或者 SetError(AuthError{}).
Post("https://myapp.com/login")
// 以原始字节数组形式进行文件上传。例如:将文件上传到Dropbox
fileBytes, _ := os.ReadFile("/Users/jeeva/mydocument.pdf")
// 注意,我们没有设置内容类型头,因为go-resty会自动检测Content-Type
resp, err := client.R().
SetBody(fileBytes).
SetContentLength(true). // Dropbox需要这个值
SetAuthToken("").
SetError(&DropboxError{}). // 或者 SetError(DropboxError{}).
Post("https://content.dropboxapi.com/1/files_put/auto/resty/mydocument.pdf") // DropBox也支持PUT方式上传
// 注意:如果没有设置内容类型头,resty会检测请求体的Content-Type
// * 对于结构体和map数据类型,默认为'application/json'
// * 然后是普通文本内容类型
同一参数名,多个参数值 #
values := make(url.Values)
values["files"] = append(values["files"], "E:\\镜像测试\\1.jpg")
values["files"] = append(values["files"], "E:\\镜像测试\\2.jpg")
client := resty.New()
resp, err := client.R().
SetContext(ctx).
SetHeader("Content-Type", "application/json").
SetHeader("model", "ch-pt-ocr-v4").
SetFormDataFromValues(values).
Post("http://127.0.0.1:9120" + videoOCRUrl)
//Post(d.AiEngineHost + videoDetectionUrl)
if err != nil {
err = fmt.Errorf("Request failed: %v", err)
return
}
defer resp.RawBody().Close()
PUT #
发出 UPDATE(PUT)请求: #
要使用 Resty v2 执行更新操作并将响应绑定到结构体中,我们可以使用 .SetResult() 方法。以下示例演示如何发送带有 JSON 有效负载的 PUT 请求并将响应绑定到结构体中:
package main
import (
"fmt"
"log"
"github.com/go-resty/resty/v2"
)
type DevUser struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
var updatedUser DevUser
payload := DevUser{
Name: "Updated Name",
Email: "updated@example.com",
}
response, err := resty.New().R().
SetHeader("Content-Type", "application/json").
SetBody(&payload).
SetResult(&updatedUser).
Put("https://api.example.com/users/123")
if err != nil {
log.Fatal(err)
}
fmt.Println("PUT Response:", response.Status())
fmt.Printf("Updated User: ID: %d, Name: %s, Email: %s\n", updatedUser.ID, updatedUser.Name, updatedUser.Email)
}
您可以像演示 POST
一样使用各种 PUT
方法调用的组合。
// 注意:这是使用PUT方法的一个示例,更多组合请参阅POST
// 创建一个Resty客户端
client := resty.New()
// 请求以JSON内容类型发送
// 如果有客户端级别的设置,可以不设置身份验证令牌,错误
resp, err := client.R().
SetBody(Article{
Title: "go-resty",
Content: "这是我的文章内容,哦耶!",
Author: "Jeevanandam M",
Tags: []string{"文章", "示例", "resty"},
}).
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
SetError(&错误{}). // 或者 SetError(Error{}).
Put("https://myapp.com/article/1234")
DELETE #
发出删除请求: #
要使用 Resty v2 发送 DELETE 请求,我们可以使用 .Delete() 方法。以下是演示删除用户的示例:
package main
import (
"fmt"
"log"
"github.com/go-resty/resty/v2"
)
type DevUser struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
response, err := resty.New().R().Delete("https://api.example.com/users/123")
if err != nil {
log.Fatal(err)
}
fmt.Println("DELETE Response:", response.Status())
}
// 创建一个Resty客户端
client := resty.New()
// 删除一篇文章
// 如果有客户端级别的设置,可以不设置身份验证令牌,错误
resp, err := client.R().
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
SetError(&错误{}). // 或者 SetError(Error{}).
Delete("https://myapp.com/articles/1234")
// 以JSON字符串作为有效载荷/内容的方式删除多篇文章
// 如果有客户端级别的设置,可以不设置身份验证令牌,错误
resp, err := client.R().
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
SetError(&错误{}). // 或者 SetError(Error{}).
SetHeader("Content-Type", "application/json").
SetBody(`{article_ids: [1002, 1006, 1007, 87683, 45432] }`).
Delete("https://myapp.com/articles")
// 获取资源的头信息
// 如果有客户端级别的设置,可以不设置身份验证令牌
resp, err := client.R().
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
Head("https://myapp.com/videos/hi-res-video")
// 获取资源的选项信息
// 如果有客户端级别的设置,可以不设置身份验证令牌
resp, err := client.R().
SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
Options("https://myapp.com/servers/nyc-dc-01")
传递标头: #
Resty v2 允许我们在请求中包含自定义标头。以下代码片段演示了如何使用 Resty v2 传递标头:
package main
import (
"fmt"
"log"
"github.com/go-resty/resty/v2"
)
type DevUser struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
client := resty.New()
client.SetHeader("Authorization", "Bearer YOUR_TOKEN")
response, err := client.R().Get("https://api.example.com/protected-resource")
if err != nil {
log.Fatal(err)
}
fmt.Println("GET with Headers Response:", response.Status())
}
设置JSON和XML序列化/反序列化操作 #
用户可以将选择的JSON/XML库注册到resty中,或者编写自己的库。默认情况下,resty分别注册标准的 encoding/json
和 encoding/xml
。
// 注册json-iterator的示例
import jsoniter "github.com/json-iterator/go"
json := jsoniter.ConfigCompatibleWithStandardLibrary
client := resty.New().
SetJSONMarshaler(json.Marshal).
SetJSONUnmarshaler(json.Unmarshal)
// 类似地,用户可以使用以下方式对XML进行设置 -
client.SetXMLMarshaler(xml.Marshal).
SetXMLUnmarshaler(xml.Unmarshal)
获取响应状态码 #
fmt.Println(resp.StatusCode())
获取响应头部信息 #
fmt.Println(resp.Header())
获取响应体数据 #
fmt.Println(resp.Body())
解析 JSON 响应数据 #
var result map[string]interface{}
err = json.Unmarshal(resp.Body(), &result)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result)
高级用法 #
除了基本的请求和响应处理,Go Resty 还提供了一些高级用法,例如连接池、超时设置、重试机制、代理等。下面是一些常见的高级用法示例:
连接池 #
client := resty.New().
SetTransport(&http.Transport{
MaxIdleConnsPerHost: 10,
})
超时设置 #
client := resty.New().
SetTimeout(10 * time.Second)
重试机制 #
client := resty.New().
SetRetryCount(3).
SetRetryWaitTime(5 * time.Second)
代理 #
client := resty.New().
SetProxy("http://proxy.example.com:8080")
结论: #
在本综合指南中,我们探讨了如何利用 Resty v2(一个易于使用的 HTTP 客户端库)在 Go 中执行 GET、POST、UPDATE 和 DELETE 请求。我们还学习了如何传递标头以增强 API 交互,从而提供更高的自定义性和安全性。此外,我们还发现了如何将 API 响应绑定到 Go 结构中,从而轻松处理和操作数据。Resty v2 简化了 RESTful API 的使用,使我们能够专注于构建强大而高效的应用程序。
记得导入 Resty v2 包(github.com/go-resty/resty/v2),有效处理错误,并调整示例以适合您的特定 API 端点和要求。