Go语言HTTP请求响应
Go语言通过net/http包提供了高效简洁的HTTP请求与响应处理能力,支持GET、POST等全系方法及高级配置(如请求头、代理、重试机制),适用于服务器开发、微服务、网络爬虫及数据聚合等场景。其并发模型(goroutine)和静态编译特性在高并发、云原生应用中表现卓越,结合结构化数据解析(JSON/HTML)和健壮的错误处理,成为构建现代Web服务与工具的首选方案。
一、核心基础:net/http包
Go语言的net/http包提供了简洁高效的HTTP客户端功能,是处理HTTP请求的标准库。它支持所有HTTP方法,能轻松处理请求和响应。
1. 基础请求结构
// 创建HTTP客户端
client := &http.Client{}
// 发送GET请求
resp, err := client.Get("https://api.example.com/data")
// 处理响应
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close() // 确保关闭响应体
// 读取响应内容
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalf("读取响应失败: %v", err)
}
fmt.Println(string(body))
二、详细请求方法与场景
1. GET请求
适用场景:获取数据(如API调用、网页抓取)
代码示例:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
)
func main() {
// 基本GET请求
resp, err := http.Get("https://jsonplaceholder.typicode.com/posts/1")
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
// 检查状态码
if resp.StatusCode != http.StatusOK {
log.Fatalf("请求失败,状态码: %d", resp.StatusCode)
}
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("读取响应失败: %v", err)
}
fmt.Println("GET请求响应:", string(body))
}
高级用法:带查询参数的GET请求
package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
// 创建URL
baseURL := "https://api.example.com/search"
params := url.Values{}
params.Add("query", "go programming")
params.Add("page", "1")
params.Add("limit", "10")
// 构建完整URL
fullURL := baseURL + "?" + params.Encode()
resp, err := http.Get(fullURL)
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("带查询参数的GET请求响应:", string(body))
}
2. POST请求
适用场景:提交数据(如表单提交、API数据提交)
代码示例:提交JSON数据
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type PostRequest struct {
Title string `json:"title"`
Body string `json:"body"`
UserID int `json:"userId"`
}
func main() {
// 创建请求数据
postData := PostRequest{
Title: "测试标题",
Body: "这是测试内容",
UserID: 1,
}
// 序列化为JSON
jsonData, err := json.Marshal(postData)
if err != nil {
log.Fatalf("JSON序列化失败: %v", err)
}
// 创建POST请求
req, err := http.NewRequest("POST", "https://jsonplaceholder.typicode.com/posts", bytes.NewBuffer(jsonData))
if err != nil {
log.Fatalf("创建请求失败: %v", err)
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
// 处理响应
if resp.StatusCode != http.StatusOK {
log.Fatalf("请求失败,状态码: %d", resp.StatusCode)
}
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("POST请求响应:", string(body))
}
代码示例:提交表单数据
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
)
func main() {
// 创建表单数据
formData := url.Values{}
formData.Add("username", "testuser")
formData.Add("password", "testpass")
formData.Add("email", "test@example.com")
// 创建POST请求
req, err := http.NewRequest("POST", "https://api.example.com/login", bytes.NewBufferString(formData.Encode()))
if err != nil {
log.Fatalf("创建请求失败: %v", err)
}
// 设置请求头
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
// 处理响应
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("表单POST请求响应:", string(body))
}
3. 处理响应数据
适用场景:解析服务器返回的数据(JSON、HTML、XML等)
JSON响应解析示例:
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type PostResponse struct {
ID int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
UserID int `json:"userId"`
}
func main() {
resp, err := http.Get("https://jsonplaceholder.typicode.com/posts/1")
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
// 解析JSON响应
var post PostResponse
if err := json.NewDecoder(resp.Body).Decode(&post); err != nil {
log.Fatalf("JSON解析失败: %v", err)
}
fmt.Printf("标题: %s\n内容: %s\n", post.Title, post.Body)
}
HTML响应处理示例:
package main
import (
"fmt"
"log"
"net/http"
"golang.org/x/net/html"
)
func main() {
resp, err := http.Get("https://example.com")
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
// 解析HTML
doc, err := html.Parse(resp.Body)
if err != nil {
log.Fatalf("HTML解析失败: %v", err)
}
// 遍历HTML节点
var f func(*html.Node)
f = func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == "h1" {
fmt.Printf("标题: %s\n", n.FirstChild.Data)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
f(c)
}
}
f(doc)
}
三、高级功能与配置
1. 设置请求头与Cookie
适用场景:模拟浏览器行为、处理认证、避免被封IP
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://httpbin.org/headers", nil)
if err != nil {
log.Fatalf("请求创建失败: %v", err)
}
// 设置请求头
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Accept-Encoding", "gzip, deflate, br")
// 设置Cookie
req.AddCookie(&http.Cookie{
Name: "session_id",
Value: "abc123xyz",
})
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
// 处理响应
body, _ := io.ReadAll(resp.Body)
fmt.Println("请求头设置成功,响应内容:", string(body))
}
2. 使用代理
适用场景:访问需要代理的网站(如Google、Instagram等)、避免IP被封
package main
import (
"fmt"
"log"
"net/http"
"net/url"
"time"
)
func main() {
// 设置代理
proxyURL, err := url.Parse("http://127.0.0.1:8080")
if err != nil {
log.Fatalf("解析代理URL失败: %v", err)
}
// 创建带代理的HTTP客户端
transport := &http.Transport{
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{
Timeout: 30 * time.Second,
Transport: transport,
}
// 发送请求
resp, err := client.Get("https://httpbin.org/ip")
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("使用代理的请求响应:", string(body))
}
3. 错误处理与重试机制
适用场景:网络不稳定时的健壮性处理
package main
import (
"fmt"
"io"
"log"
"net/http"
"time"
)
func fetchWithRetry(url string, maxRetries int) ([]byte, error) {
var respBody []byte
for i := 0; i <= maxRetries; i++ {
resp, err := http.Get(url)
if err == nil && resp.StatusCode == http.StatusOK {
respBody, err = io.ReadAll(resp.Body)
resp.Body.Close()
return respBody, err
}
if i < maxRetries {
waitTime := time.Duration(i*2) * time.Second
log.Printf("请求失败,重试中... (尝试 %d/%d) 等待 %v", i+1, maxRetries, waitTime)
time.Sleep(waitTime)
}
}
return nil, fmt.Errorf("请求失败,最大重试次数已用尽")
}
func main() {
url := "https://jsonplaceholder.typicode.com/posts/1"
body, err := fetchWithRetry(url, 3)
if err != nil {
log.Fatalf("最终请求失败: %v", err)
}
fmt.Println("成功获取响应:", string(body))
}
四、Go语言HTTP请求的适用场景分析
1. 服务器编程与API开发
适用场景:构建高性能Web服务器、RESTful API
Go语言的goroutine和channel机制使得它能轻松处理大量并发请求。在Web开发中,Go语言的net/http包是构建服务器的核心。
代码示例:简单API服务器
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
var users = []User{
{ID: 1, Name: "张三", Email: "zhangsan@example.com"},
{ID: 2, Name: "李四", Email: "lisi@example.com"},
}
func getUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func getUser(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
if id == "" {
http.Error(w, "缺少ID参数", http.StatusBadRequest)
return
}
// 模拟数据库查询
for _, user := range users {
if fmt.Sprintf("%d", user.ID) == id {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
return
}
}
http.Error(w, "用户未找到", http.StatusNotFound)
}
func main() {
http.HandleFunc("/users", getUsers)
http.HandleFunc("/user", getUser)
fmt.Println("服务器启动在:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
2. 云计算与微服务
适用场景:Kubernetes、Docker等云原生应用开发
Go语言的静态编译和高效性能使其成为云原生应用的首选语言。Kubernetes就是用Go语言编写的。
代码示例:服务发现
package main
import (
"fmt"
"io"
"log"
"net/http"
"time"
)
// 模拟服务发现
func discoverService(serviceName string) (string, error) {
// 模拟服务发现调用
fmt.Printf("正在发现服务: %s\n", serviceName)
// 模拟延迟
time.Sleep(500 * time.Millisecond)
// 模拟返回服务地址
if serviceName == "user-service" {
return "http://user-service:8080", nil
}
return "", fmt.Errorf("服务未找到: %s", serviceName)
}
func main() {
// 发现服务
userServiceURL, err := discoverService("user-service")
if err != nil {
log.Fatalf("服务发现失败: %v", err)
}
// 使用服务
client := &http.Client{}
resp, err := client.Get(userServiceURL + "/users")
if err != nil {
log.Fatalf("调用用户服务失败: %v", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("用户服务响应: %s\n", string(body))
}
3. 网络爬虫
适用场景:数据抓取、信息收集
Go语言的并发处理能力使其非常适合开发高性能爬虫。
代码示例:简单爬虫
package main
import (
"fmt"
"log"
"net/http"
"golang.org/x/net/html"
"sync"
)
func crawl(url string, wg *sync.WaitGroup) {
defer wg.Done()
resp, err := http.Get(url)
if err != nil {
log.Printf("请求失败: %v", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Printf("请求失败,状态码: %d", resp.StatusCode)
return
}
// 解析HTML
doc, err := html.Parse(resp.Body)
if err != nil {
log.Printf("HTML解析失败: %v", err)
return
}
// 提取链接
var links []string
var f func(*html.Node)
f = func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == "a" {
for _, attr := range n.Attr {
if attr.Key == "href" {
links = append(links, attr.Val)
break
}
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
f(c)
}
}
f(doc)
fmt.Printf("从 %s 抓取到 %d 个链接\n", url, len(links))
}
func main() {
urls := []string{
"https://example.com",
"https://golang.org",
"https://github.com",
}
var wg sync.WaitGroup
wg.Add(len(urls))
for _, url := range urls {
go crawl(url, &wg)
}
wg.Wait()
fmt.Println("所有爬取任务完成")
}
4. 数据处理与分析
适用场景:数据清洗、API数据聚合
Go语言的高性能和并发能力使其适合处理大量数据。
代码示例:聚合API数据
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"sync"
)
type WeatherData struct {
City string `json:"city"`
Temp float64 `json:"temp"`
Humidity float64 `json:"humidity"`
}
func fetchWeather(city string) (*WeatherData, error) {
url := fmt.Sprintf("https://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q=%s", city)
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var weatherData WeatherData
if err := json.NewDecoder(resp.Body).Decode(&weatherData); err != nil {
return nil, err
}
return &weatherData, nil
}
func main() {
cities := []string{"Beijing", "Shanghai", "Guangzhou", "Shenzhen"}
var wg sync.WaitGroup
var results = make([]WeatherData, len(cities))
for i, city := range cities {
wg.Add(1)
go func(i int, city string) {
defer wg.Done()
data, err := fetchWeather(city)
if err != nil {
log.Printf("获取天气数据失败: %s - %v", city, err)
return
}
results[i] = *data
}(i, city)
}
wg.Wait()
// 打印结果
for i, city := range cities {
fmt.Printf("%s: 温度 %.1f°C, 湿度 %.1f%%\n", city, results[i].Temp, results[i].Humidity)
}
}
五、最佳实践与注意事项
- 始终关闭响应体:使用defer resp.Body.Close()防止资源泄漏
- 检查状态码:不要只检查错误,也要检查HTTP状态码
- 使用正确的Content-Type:发送JSON数据时设置Content-Type: application/json
- 避免默认ServeMux:在Web应用中使用自定义ServeMux,避免安全风险
- 处理超时:设置合理的请求超时时间
- 错误处理:不要忽略错误,提供有意义的错误信息
- 使用结构体解析:避免使用map解析JSON,使用结构体更安全
六、总结
Go语言的net/http包提供了强大而简洁的HTTP请求响应处理能力,适用于:
- 服务器编程:构建高性能Web服务器和API
- 云计算与微服务:Kubernetes、Docker等云原生应用
- 网络爬虫:高效抓取网页数据
- 数据处理:聚合和处理API数据
- 系统工具:开发网络工具和系统工具
Go语言的并发模型(goroutine)和简洁语法使其在处理HTTP请求时表现出色,特别是在高并发场景下。掌握HTTP请求响应处理是Go语言开发的必备技能,也是构建现代Web应用和云原生应用的基础。
小贴士:Go语言的HTTP客户端处理是很多高级框架(如Gin、Echo)的基础,掌握这些基础知识将让你更容易理解和使用这些框架。
- 感谢你赐予我前进的力量

