Golang中如何在请求体中查找特定键值?未找到时如何报错处理
Golang中如何在请求体中查找特定键值?未找到时如何报错处理
这是我的 HandleFunc。
type User struct {
Username string `json:"username"`
Password string `json:"password"`
}
type ResponseResult struct {
Error string `json:"error"`
Result string `json:"result"`
}
func Registration(w http.ResponseWriter, r *http.Request) {
var res ResponseResult
w.Header().Set("Content-Type", "application/json")
body, err := ioutil.ReadAll(r.Body)
// 没有 JSON 请求体
if err != nil {
res.Error = err.Error()
// 返回 400 状态码
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
}
如果请求中没有传递任何 JSON 数据体,这段代码工作正常。
但我希望,如果提供了错误的数据,它也应该报错。例如,我不希望以下数据被视为正确:
{
"usernm": "foo",
"passwd": "bar"
}
这是我正在使用的代码:
var user model.User
// 检查是否接收到有效数据,即用户名和密码
err = json.Unmarshal(body, &user)
// JSON 请求体中的键不正确
if err != nil {
res.Error = "发送的数据不正确。请参阅 API 文档。"
// 返回 400 状态码
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
res.Result = "无异常"
json.NewEncoder(w).Encode(res)
即使请求体是错误的,我在 json.Unmarshal 处也没有收到任何错误。
更多关于Golang中如何在请求体中查找特定键值?未找到时如何报错处理的实战教程也可以访问 https://www.itying.com/category-94-b0.html
4 回复
defer r.Body.Close() 应在错误检查块之后调用。
更多关于Golang中如何在请求体中查找特定键值?未找到时如何报错处理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我也尝试过使用 json.Decode:
err := json.NewDecoder(r.Body).Decode(&user)
// 没有 JSON 请求体
if err != nil {
res.Error = err.Error()
// 返回 400 状态码
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
但由于解码过程没有错误,这段代码块无法被执行到。
使用解码器中的 DisallowUnknownFields 方法:
jsonDecoder := json.NewDecoder(r.Body)
jsonDecoder.DisallowUnknownFields()
defer r.Body.Close()
// 检查是否存在正确的JSON正文或错误
if err := jsonDecoder.Decode(&user); err != nil {
res.Error = err.Error()
// 返回400状态码
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
在Golang中处理JSON请求体时,json.Unmarshal不会因为JSON中存在额外字段而报错。要确保请求体包含特定键值,需要在反序列化后手动验证。以下是修改后的代码:
func Registration(w http.ResponseWriter, r *http.Request) {
var res ResponseResult
w.Header().Set("Content-Type", "application/json")
// 读取请求体
body, err := ioutil.ReadAll(r.Body)
if err != nil {
res.Error = "无法读取请求体"
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
// 使用map接收JSON以检查额外字段
var rawData map[string]interface{}
if err := json.Unmarshal(body, &rawData); err != nil {
res.Error = "无效的JSON格式"
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
// 检查必需字段是否存在
requiredFields := []string{"username", "password"}
for _, field := range requiredFields {
if _, exists := rawData[field]; !exists {
res.Error = fmt.Sprintf("缺少必需字段: %s", field)
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
}
// 检查是否有额外字段
allowedFields := map[string]bool{
"username": true,
"password": true,
}
for field := range rawData {
if !allowedFields[field] {
res.Error = fmt.Sprintf("不允许的字段: %s", field)
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
}
// 反序列化到User结构体
var user User
if err := json.Unmarshal(body, &user); err != nil {
res.Error = "数据格式错误"
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
// 验证字段值不为空
if user.Username == "" || user.Password == "" {
res.Error = "用户名和密码不能为空"
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
res.Result = "注册成功"
json.NewEncoder(w).Encode(res)
}
更简洁的验证方案是使用json.Decoder的DisallowUnknownFields方法:
func Registration(w http.ResponseWriter, r *http.Request) {
var res ResponseResult
w.Header().Set("Content-Type", "application/json")
var user User
decoder := json.NewDecoder(r.Body)
decoder.DisallowUnknownFields() // 禁止未知字段
if err := decoder.Decode(&user); err != nil {
res.Error = fmt.Sprintf("请求数据错误: %v", err)
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
// 验证必需字段
if user.Username == "" || user.Password == "" {
res.Error = "用户名和密码不能为空"
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
res.Result = "注册成功"
json.NewEncoder(w).Encode(res)
}
如果需要更复杂的验证,可以使用go-playground/validator包:
import "github.com/go-playground/validator/v10"
type User struct {
Username string `json:"username" validate:"required,min=3,max=32"`
Password string `json:"password" validate:"required,min=8"`
}
func Registration(w http.ResponseWriter, r *http.Request) {
var res ResponseResult
w.Header().Set("Content-Type", "application/json")
var user User
decoder := json.NewDecoder(r.Body)
decoder.DisallowUnknownFields()
if err := decoder.Decode(&user); err != nil {
res.Error = fmt.Sprintf("请求数据错误: %v", err)
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
// 使用validator进行验证
validate := validator.New()
if err := validate.Struct(user); err != nil {
res.Error = fmt.Sprintf("验证失败: %v", err)
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(res)
return
}
res.Result = "注册成功"
json.NewEncoder(w).Encode(res)
}

