3. JSON 请求与响应处理
任务说明
实现一个 HTTP 服务,接收客户端发送的 JSON 请求体,解析后返回 JSON 响应。要求包含两类错误处理:请求体格式非法时返回 400 状态码及错误信息;请求体合法但业务校验失败时返回 422 状态码及具体字段错误。通过 curl 命令验证完整闭环。
核心实现
package main
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"strings"
)
// User 定义请求与响应共用的数据结构
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
// ErrorResponse 统一错误响应结构
type ErrorResponse struct {
Error string `json:"error"`
}
// validateUser 业务校验:name非空,email包含@,age在0-120之间
func validateUser(u *User) error {
var msgs []string
if strings.TrimSpace(u.Name) == "" {
msgs = append(msgs, "name is required")
}
if !strings.Contains(u.Email, "@") {
msgs = append(msgs, "email must contain @")
}
if u.Age < 0 || u.Age > 120 {
msgs = append(msgs, "age must be between 0 and 120")
}
if len(msgs) > 0 {
return errors.New(strings.Join(msgs, "; "))
}
return nil
}
func userHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// 仅接受 POST 方法
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
json.NewEncoder(w).Encode(ErrorResponse{Error: "method not allowed"})
return
}
// 解析 JSON 请求体
var req User
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&req); err != nil {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(ErrorResponse{Error: "invalid JSON body: " + err.Error()})
return
}
// 业务校验
if err := validateUser(&req); err != nil {
w.WriteHeader(http.StatusUnprocessableEntity)
json.NewEncoder(w).Encode(ErrorResponse{Error: err.Error()})
return
}
// 构造成功响应(回显数据并附加状态字段)
resp := map[string]interface{}{
"status": "ok",
"user": req,
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(resp)
}
func main() {
http.HandleFunc("/user", userHandler)
addr := ":8080"
fmt.Printf("Server listening on %s\n", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}
接口与错误处理逻辑
// 请求示例
POST /user
Content-Type: application/json
{"name":"Alice","email":"alice@example.com","age":30}
// 成功响应 (200)
{"status":"ok","user":{"name":"Alice","email":"alice@example.com","age":30}}
// 非法JSON (400)
{"error":"invalid JSON body: invalid character 'x' looking for beginning of value"}
// 业务校验失败 (422)
{"error":"name is required; email must contain @; age must be between 0 and 120"}
运行与验证
# 1. 启动服务
go run main.go
# 2. 验证成功场景(预期返回200及回显数据)
curl -i -X POST http://localhost:8080/user \
-H "Content-Type: application/json" \
-d '{"name":"Alice","email":"alice@example.com","age":30}'
# 3. 验证非法JSON(预期返回400及错误信息)
curl -i -X POST http://localhost:8080/user \
-H "Content-Type: application/json" \
-d '{invalid json}'
# 4. 验证业务校验失败(预期返回422及字段错误)
curl -i -X POST http://localhost:8080/user \
-H "Content-Type: application/json" \
-d '{"name":"","email":"bad-email","age":200}'
判定标准
- 成功请求返回 HTTP 200,响应体包含
status:"ok"及回显的 user 对象; - 请求体无法解析为合法 JSON 时返回 HTTP 400,错误信息以
invalid JSON body:开头; - JSON 合法但字段不满足校验规则时返回 HTTP 422,错误信息列出所有未通过的具体字段原因;
- 非 POST 请求返回 HTTP 405。