jee said
Go语言HTTP客户端开发
Go语言的net/http包提供了强大的HTTP客户端功能。本文将介绍如何使用Go语言进行HTTP客户端开发。
基本HTTP请求
GET请求
import (
"fmt"
"io"
"net/http"
)
func main() {
// 发送GET请求
resp, err := http.Get("https://api.example.com/data")
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
// 读取响应体
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("读取响应失败:", err)
return
}
fmt.Println("状态码:", resp.StatusCode)
fmt.Println("响应体:", string(body))
}POST请求
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
user := User{Name: "张三", Email: "zhangsan@example.com"}
// 序列化为JSON
jsonData, _ := json.Marshal(user)
// 发送POST请求
resp, err := http.Post(
"https://api.example.com/users",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
fmt.Println("状态码:", resp.StatusCode)
}PUT和DELETE请求
func main() {
// PUT请求
req, _ := http.NewRequest("PUT", "https://api.example.com/users/1", nil)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
// DELETE请求
req2, _ := http.NewRequest("DELETE", "https://api.example.com/users/1", nil)
resp2, err := client.Do(req2)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp2.Body.Close()
}自定义HTTP客户端
设置超时
import (
"net/http"
"time"
)
func main() {
// 创建自定义客户端
client := &http.Client{
Timeout: 10 * time.Second, // 10秒超时
}
resp, err := client.Get("https://api.example.com/data")
if err != nil {
fmt.Println("请求超时:", err)
return
}
defer resp.Body.Close()
}设置请求头
func main() {
req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)
// 设置请求头
req.Header.Set("Authorization", "Bearer token123")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "MyApp/1.0")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
}重定向控制
func main() {
client := &http.Client{
// 不自动跟随重定向
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
resp, err := client.Get("https://api.example.com/redirect")
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
}JSON处理
解析JSON响应
import (
"encoding/json"
"fmt"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt string `json:"created_at"`
}
func main() {
resp, err := http.Get("https://api.example.com/users/1")
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
var user User
err = json.NewDecoder(resp.Body).Decode(&user)
if err != nil {
fmt.Println("解析JSON失败:", err)
return
}
fmt.Printf("%+v\n", user)
}发送JSON请求
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
type CreateUserRequest struct {
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
reqBody := CreateUserRequest{
Name: "张三",
Email: "zhangsan@example.com",
}
jsonData, _ := json.Marshal(reqBody)
req, _ := http.NewRequest(
"POST",
"https://api.example.com/users",
bytes.NewBuffer(jsonData),
)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
}表单处理
发送表单数据
import (
"fmt"
"net/http"
"net/url"
)
func main() {
// 创建表单数据
formData := url.Values{}
formData.Set("username", "zhangsan")
formData.Set("password", "password123")
formData.Set("remember", "true")
// 编码表单数据
encodedData := formData.Encode()
// 发送POST请求
resp, err := http.PostForm(
"https://api.example.com/login",
formData,
)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
fmt.Println("状态码:", resp.StatusCode)
}文件上传
import (
"bytes"
"fmt"
"mime/multipart"
"net/http"
"os"
)
func main() {
// 打开要上传的文件
file, err := os.Open("document.pdf")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()
// 创建multipart表单
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// 添加文件字段
part, err := writer.CreateFormFile("file", "document.pdf")
if err != nil {
fmt.Println("创建表单文件失败:", err)
return
}
io.Copy(part, file)
// 添加其他字段
writer.WriteField("description", "重要文档")
writer.Close()
// 创建请求
req, _ := http.NewRequest("POST", "https://api.example.com/upload", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("上传失败:", err)
return
}
defer resp.Body.Close()
}Cookie处理
发送Cookie
func main() {
req, _ := http.NewRequest("GET", "https://api.example.com/data", nil)
// 添加Cookie
req.AddCookie(&http.Cookie{
Name: "session_id",
Value: "abc123",
})
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
}读取Cookie
func main() {
resp, err := http.Get("https://api.example.com/login")
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
// 读取响应中的Cookie
for _, cookie := range resp.Cookies() {
fmt.Printf("Cookie: %s = %s\n", cookie.Name, cookie.Value)
}
}错误处理
网络错误处理
func makeRequest(url string) error {
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("请求失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return fmt.Errorf("HTTP错误: %d", resp.StatusCode)
}
return nil
}
func main() {
err := makeRequest("https://api.example.com/data")
if err != nil {
fmt.Println("请求出错:", err)
return
}
fmt.Println("请求成功")
}重试机制
import (
"fmt"
"net/http"
"time"
)
func retryRequest(url string, maxRetries int) (*http.Response, error) {
var resp *http.Response
var err error
for i := 0; i < maxRetries; i++ {
resp, err = http.Get(url)
if err == nil && resp.StatusCode < 500 {
return resp, nil
}
if i < maxRetries-1 {
fmt.Printf("重试 %d/%d\n", i+1, maxRetries)
time.Sleep(time.Second * time.Duration(i+1))
}
}
return resp, err
}
func main() {
resp, err := retryRequest("https://api.example.com/data", 3)
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
}最佳实践
- 设置合理的超时:避免请求长时间阻塞
- 使用连接池:对于大量请求使用http.Client的连接池
- 处理错误状态码:检查HTTP状态码并相应处理
- 关闭响应体:使用defer确保响应体被关闭
- 使用结构体处理JSON:定义结构体来映射JSON数据
总结
Go语言的HTTP客户端功能强大而简洁,通过net/http包可以轻松完成各种HTTP请求任务。掌握HTTP客户端开发对于现代Web应用开发至关重要。