在Golang的标准库中,net/http包是处理HTTP相关操作的核心组件,它既可以用来搭建HTTP服务器,也可以作为HTTP客户端发送各类请求,其中POST请求的发送是客户端场景下的常见需求,适用于数据提交、接口调用等多种业务场景。

基础POST请求发送流程
使用net/http发送POST请求的核心步骤分为四步:构造请求体、创建HTTP客户端、发送请求、处理响应。下面先以发送表单数据为例,展示最基础的POST请求实现方式。
发送表单类型POST请求
表单类型的POST请求需要将数据编码为application/x-www-form-urlencoded格式,Golang的net/url包提供了对应的编码方法。
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
func main() {
// 构造表单数据
formData := url.Values{}
formData.Set("username", "test_user")
formData.Set("password", "test_pass")
// 创建请求
resp, err := http.Post(
"http://127.0.0.1:8080/login",
"application/x-www-form-urlencoded",
strings.NewReader(formData.Encode()),
)
if err != nil {
fmt.Printf("发送请求失败: %vn", err)
return
}
defer resp.Body.Close()
// 读取响应内容
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("读取响应失败: %vn", err)
return
}
fmt.Printf("响应状态码: %dn", resp.StatusCode)
fmt.Printf("响应内容: %sn", body)
}
发送JSON类型POST请求
在接口调用场景中,JSON格式是更常用的请求体格式,需要设置Content-Type为application/json,同时将结构体序列化为JSON字符串作为请求体。
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
// 定义请求参数结构体
type UserRequest struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
}
func main() {
// 构造请求参数
reqData := UserRequest{
Name: "张三",
Age: 25,
Email: "test@ipipp.com",
}
// 序列化结构体为JSON
jsonData, err := json.Marshal(reqData)
if err != nil {
fmt.Printf("JSON序列化失败: %vn", err)
return
}
// 创建HTTP请求
req, err := http.NewRequest("POST", "http://127.0.0.1:8080/user/add", bytes.NewBuffer(jsonData))
if err != nil {
fmt.Printf("创建请求失败: %vn", err)
return
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer test_token")
// 创建客户端并发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Printf("发送请求失败: %vn", err)
return
}
defer resp.Body.Close()
// 处理响应
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("读取响应失败: %vn", err)
return
}
fmt.Printf("响应状态码: %dn", resp.StatusCode)
fmt.Printf("响应内容: %sn", body)
}
进阶使用技巧
设置请求超时时间
默认的HTTP客户端没有超时限制,在网络异常时可能导致请求一直阻塞,实际开发中需要为客户端设置合理的超时时间。
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
func main() {
formData := url.Values{}
formData.Set("key", "value")
// 创建带超时设置的客户端,超时时间设为5秒
client := &http.Client{
Timeout: 5 * time.Second,
}
resp, err := client.Post(
"http://127.0.0.1:8080/api",
"application/x-www-form-urlencoded",
strings.NewReader(formData.Encode()),
)
if err != nil {
fmt.Printf("请求失败: %vn", err)
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("响应内容: %sn", body)
}
处理不同类型的响应
如果响应内容是JSON格式,可以直接将其反序列化为对应的结构体,避免手动解析字符串。
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
// 定义响应结构体
type ApiResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Data string `json:"data"`
}
func main() {
resp, err := http.Post("http://127.0.0.1:8080/api", "application/json", nil)
if err != nil {
fmt.Printf("请求失败: %vn", err)
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var apiResp ApiResponse
// 反序列化响应内容
err = json.Unmarshal(body, &apiResp)
if err != nil {
fmt.Printf("响应解析失败: %vn", err)
return
}
fmt.Printf("响应码: %d, 消息: %s, 数据: %sn", apiResp.Code, apiResp.Message, apiResp.Data)
}
常见问题说明
- 请求发送后一定要调用
resp.Body.Close(),避免资源泄露,建议使用defer语句在请求成功后立即注册关闭操作。 - 如果请求需要携带自定义请求头,建议使用
http.NewRequest创建请求对象后再通过Header.Set方法设置,比直接使用http.Post更灵活。 - 生产环境中不要忽略错误处理,网络请求存在失败的可能,需要针对超时、连接拒绝等错误做对应的容错处理。