在Go语言的后端开发中,使用标准库的net_http包编写HTTP服务时,经常需要在处理函数中获取客户端发送的POST请求参数,不同类型的POST参数获取方式存在差异,下面逐一介绍常见的实现方法。

获取表单类型POST参数
当客户端发送的是application/x-www-form-urlencoded或者multipart/form-data类型的POST请求时,可以通过r.ParseForm()或者r.ParseMultipartForm()方法解析参数,之后从对应的字段中获取值。
首先看application/x-www-form-urlencoded类型的参数获取示例:
package main
import (
"fmt"
"net/http"
)
func formPostHandler(w http.ResponseWriter, r *http.Request) {
// 只允许POST请求
if r.Method != http.MethodPost {
http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed)
return
}
// 解析表单参数,该方法会同时解析URL查询参数和POST表单参数
err := r.ParseForm()
if err != nil {
http.Error(w, "解析参数失败", http.StatusBadRequest)
return
}
// 获取单个参数,返回字符串类型
username := r.FormValue("username")
// 获取同名多个参数,返回字符串切片
hobbies := r.Form["hobbies"]
fmt.Fprintf(w, "用户名:%s,爱好:%v", username, hobbies)
}
func main() {
http.HandleFunc("/form-post", formPostHandler)
http.ListenAndServe(":8080", nil)
}
如果是multipart/form-data类型的表单,比如包含文件上传的场景,需要使用r.ParseMultipartForm()方法,参数是内存缓存的最大字节数,超过的部分会存储到临时文件:
func multipartFormHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed)
return
}
// 解析multipart表单,最大使用10MB内存
err := r.ParseMultipartForm(10 << 20)
if err != nil {
http.Error(w, "解析参数失败", http.StatusBadRequest)
return
}
// 获取普通表单参数
age := r.MultipartForm.Value["age"][0]
// 获取上传的文件
file, fileHeader, err := r.MultipartForm.File["upload_file"][0]
if err != nil {
http.Error(w, "获取文件失败", http.StatusBadRequest)
return
}
defer file.Close()
fmt.Fprintf(w, "年龄:%s,文件名:%s", age, fileHeader.Filename)
}
获取JSON格式POST参数
当前后端分离开发中,客户端经常以application/json格式发送POST请求,此时需要读取请求体中的原始数据,再反序列化到对应的结构体或者map中。
首先定义对应的结构体来接收参数:
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
}
func jsonPostHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed)
return
}
// 检查请求头的内容类型
contentType := r.Header.Get("Content-Type")
if contentType != "application/json" {
http.Error(w, "只支持JSON格式请求", http.StatusUnsupportedMediaType)
return
}
// 读取请求体
body := make([]byte, r.ContentLength)
_, err := r.Body.Read(body)
if err != nil {
http.Error(w, "读取请求体失败", http.StatusBadRequest)
return
}
defer r.Body.Close()
// 反序列化JSON
var user User
err = json.Unmarshal(body, &user)
if err != nil {
http.Error(w, "解析JSON失败", http.StatusBadRequest)
return
}
fmt.Fprintf(w, "用户信息:姓名%s,年龄%d,邮箱%s", user.Name, user.Age, user.Email)
}
如果不想定义结构体,也可以使用map来接收JSON参数:
func jsonMapHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed)
return
}
var paramMap map[string]interface{}
err := json.NewDecoder(r.Body).Decode(¶mMap)
if err != nil {
http.Error(w, "解析JSON失败", http.StatusBadRequest)
return
}
defer r.Body.Close()
fmt.Fprintf(w, "参数内容:%v", paramMap)
}
获取原始POST请求体参数
如果POST参数的格式不是上述常见类型,需要直接获取原始的请求体内容,可以通过r.Body读取,注意读取完成后要关闭请求体。
func rawBodyHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed)
return
}
// 读取原始请求体
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "读取请求体失败", http.StatusBadRequest)
return
}
defer r.Body.Close()
fmt.Fprintf(w, "原始请求体内容:%s", string(body))
}
注意事项
r.ParseForm()和r.ParseMultipartForm()方法内部会读取请求体,调用之后如果再读取r.Body会得到空内容,因此不要重复解析。- 读取请求体后一定要调用
r.Body.Close()释放资源,避免内存泄漏。 - 处理JSON参数时,建议先校验
Content-Type请求头,避免非JSON请求导致的解析错误。 - 获取参数后需要根据业务场景做合法性校验,避免无效参数影响业务逻辑。