如何在Golang中使用net/http处理HTTP请求_发送和接收数据

Go中HTTP收发核心是服务端(http.ServeMux+ListenAndServe)与客户端(http.Client+NewRequest)分工:服务端用HandleFunc注册处理器,响应JSON等;客户端需自定义Client设超时,正确处理Body读写与关闭。

在 Go 中用 net/http 发送和接收 HTTP 数据非常直接,核心在于理解服务端(http.ServeMux + http.ListenAndServe)和客户端(http.Client + http.NewRequest)两种角色的分工。

接收请求:写一个简单的 HTTP 服务

服务端主要靠注册处理器函数来响应不同路径的请求。Go 内置的 http.HandleFunc 是最简方式:

  • 它自动帮你把路径和函数绑定,并处理底层连接、解析请求头/体等细节
  • 处理器函数签名固定为 func(http.ResponseWriter, *http.Request)
  • http.ResponseWriter 用于写响应状态码、头、正文;*http.Request 包含所有请求信息(URL、Method、Header、Body、Form 等)

示例:启动一个返回 JSON 的 /api/user 接口

package main

import ( "encoding/json" "net/http" )

type User struct { ID int json:"id" Name string json:"name" }

func userHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(User{ID: 123, Name: "Alice"}) }

func main() { http.HandleFunc("/api/user", userHandler) http.ListenAndServe(":8080", nil) // 启动服务器 }

读取请求数据:表单、JSON、查询参数和原始 Body

根据前端传来的数据格式,选择对应方式解析:

  • 查询参数(URL 中 ?key=value):用 r.URL.Query().Get("key")r.FormValue("key")(后者会自动调用 ParseForm
  • 表单数据(application/x-www-form-urlencoded):先调用 r.ParseForm(),再用 r.PostFormValue("field")
  • JSON 请求体:用 json.NewDecoder(r.Body).Decode(&v),注意 r.Body 只能读一次,需提前检查 Content-Type
  • 原始字节流(如文件上传、自定义协议):用 io.ReadAll(r.Body),记得关闭或 defer r.Body.Close()

发送请求:用 http.Client 控制超时和重试

不要直接用 http.Get 这类快捷函数——它们用默认 client,无法设超时,容易阻塞。推荐显式创建带配置的 http.Client

  • 设置 Timeout 防止请求无限挂起(例如网络故障时)
  • 可选配 Transport 控制连接复用、TLS 设置、代理等
  • http.NewRequest 构造请求,手动设置 Header、Body(比如加 Authorization、发 JSON)

示例:POST 一个 JSON 到远程 API

client := &http.Client{
    Timeout: 5 * time.Second,
}
req, _ := http.NewRequest("POST", "https://api.example.com/data", strings.NewReader(`{"name":"Bob"}`))
req.Header.Set("Content-Type", "application/json")

resp, err := client.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body) fmt.Printf("Status: %s, Body: %s", resp.Status, string(body))

常见陷阱与建议

  • http.Request.Bodyio.ReadCloser,必须 Close(),否则连接不释放,可能耗尽资源
  • http.Error(w, msg, code) 快速返回错误响应,比手动写状态码更安全
  • 避免在 handler 中启协程处理耗时任务后直接返回——要确保响应已写出,否则客户端收不到
  • 生产环境别用 nil 作为 http.ListenAndServe 的第二个参数,应传入自定义 http.ServeMuxhttp.Handler 方便测试和扩展