在Golang Web服务开发中,HTTP请求参数通常分为URL查询参数、表单参数、JSON请求体参数、路径参数等不同类型,不同的参数类型对应不同的读取方式,下面会逐一介绍具体的实现方法。

URL查询参数读取
URL查询参数是拼接在请求URL后面的键值对,格式为?key1=value1&key2=value2,Golang标准库的net/http包提供了直接获取这类参数的方法。
我们可以通过Request结构体的URL.Query()方法获取所有查询参数,该方法返回一个url.Values类型,本质是map[string][]string,可以通过键名获取对应的参数值数组,再取第一个元素得到单个参数值。
package main
import (
"fmt"
"net/http"
)
func queryParamHandler(w http.ResponseWriter, r *http.Request) {
// 解析URL查询参数
queryParams := r.URL.Query()
// 获取单个参数,取数组第一个元素
name := queryParams.Get("name")
age := queryParams.Get("age")
fmt.Fprintf(w, "查询参数name: %s, age: %s", name, age)
}
func main() {
http.HandleFunc("/query", queryParamHandler)
http.ListenAndServe(":8080", nil)
}
表单参数读取
表单参数通常出现在POST、PUT等请求的请求体中,Content-Type为application/x-www-form-urlencoded或者multipart/form-data,读取前需要先调用ParseForm或者ParseMultipartForm方法解析请求体。
解析完成后可以通过PostForm字段获取表单参数,同样使用Get方法获取单个参数值,如果是文件上传类的表单,还需要额外处理文件部分。
package main
import (
"fmt"
"net/http"
)
func formParamHandler(w http.ResponseWriter, r *http.Request) {
// 解析表单参数,最大内存限制为10MB
err := r.ParseMultipartForm(10 << 20)
if err != nil {
http.Error(w, "解析表单失败", http.StatusBadRequest)
return
}
// 获取表单参数
username := r.PostForm.Get("username")
password := r.PostForm.Get("password")
fmt.Fprintf(w, "表单参数username: %s, password: %s", username, password)
}
func main() {
http.HandleFunc("/form", formParamHandler)
http.ListenAndServe(":8080", nil)
}
JSON请求体参数读取
当前端发送JSON格式的请求体时,Content-Type通常为application/json,我们需要先读取请求体的内容,再将其反序列化到对应的结构体中。
可以使用io.ReadAll读取请求体,然后通过encoding/json包的Unmarshal方法完成反序列化,注意要提前定义好和JSON结构匹配的结构体,结构体字段需要导出并且添加json标签对应JSON的键名。
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
// 定义接收JSON参数的结构体
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
func jsonParamHandler(w http.ResponseWriter, r *http.Request) {
// 读取请求体
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "读取请求体失败", http.StatusBadRequest)
return
}
defer r.Body.Close()
var user User
// 反序列化JSON
err = json.Unmarshal(body, &user)
if err != nil {
http.Error(w, "解析JSON失败", http.StatusBadRequest)
return
}
fmt.Fprintf(w, "JSON参数name: %s, email: %s", user.Name, user.Email)
}
func main() {
http.HandleFunc("/json", jsonParamHandler)
http.ListenAndServe(":8080", nil)
}
路径参数读取
路径参数是直接拼接在URL路径中的参数,比如/user/123中的123就是用户ID路径参数,标准库的net/http包本身不直接支持路径参数解析,我们可以通过第三方路由库比如gorilla/mux来实现,也可以自己手动解析路径。
下面的示例使用了gorilla/mux库,通过定义路由时添加占位符来匹配路径参数,再通过mux.Vars方法获取参数值。
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func pathParamHandler(w http.ResponseWriter, r *http.Request) {
// 获取路径参数
vars := mux.Vars(r)
userId := vars["id"]
fmt.Fprintf(w, "路径参数用户ID: %s", userId)
}
func main() {
r := mux.NewRouter()
// 定义路径参数路由,{id}为占位符
r.HandleFunc("/user/{id}", pathParamHandler)
http.ListenAndServe(":8080", r)
}
不同参数类型的适用场景
我们可以根据实际的业务场景选择合适的参数传递方式:
- URL查询参数适合传递非敏感的过滤、分页类参数,比如列表接口的页码、每页数量参数。
- 表单参数适合传统的表单提交场景,比如用户登录、信息提交的场景。
- JSON请求体参数适合传递结构复杂、数据量较大的参数,比如创建订单、提交复杂业务数据的场景。
- 路径参数适合传递资源的唯一标识,比如获取单个用户、单个商品的详情的场景。
注意事项
在读取请求参数时需要注意几个问题:首先是要做好参数校验,避免空值、非法格式的参数导致业务逻辑异常;其次是敏感参数不要放在URL查询参数中,因为URL会被记录在日志、浏览器历史中,容易泄露;最后是读取请求体后如果需要重复读取,要提前保存请求体的内容,因为请求体只能读取一次。