Go语言中调用/user/{user_id}路由时,如何处理用户ID不存在于数据库的错误
Go语言中/user/{user_id}路由的用户不存在错误处理方案
在处理带用户ID的路由时,核心是精准区分「参数错误」「用户不存在」「服务器内部错误」三种场景,返回符合HTTP规范的响应,同时做好日志留存以便排查。
具体处理步骤
- 解析并校验路由参数:先将路径中的
user_id转换为数据库支持的类型(如int、UUID),转换失败直接返回400(Bad Request),提示参数无效。 - 查询数据库并区分错误类型:调用查询函数后,优先判断是否为
sql.ErrNoRows(或自定义的「用户不存在」错误),再处理其他数据库异常(如连接失败、SQL语法错误)。 - 返回标准化响应:用户不存在返回404(Not Found)并附带友好的JSON提示;服务器内部错误返回500(Internal Server Error);参数错误返回400。
- 记录关键日志:把错误详情、请求路径、用户ID等信息记入日志,方便后续排查问题。
代码示例
1. 路由处理函数
import ( "encoding/json" "errors" "log" "net/http" "strconv" "database/sql" "github.com/gorilla/mux" ) func getUserHandler(w http.ResponseWriter, r *http.Request) { // 解析路由参数 vars := mux.Vars(r) userIDStr, ok := vars["user_id"] if !ok { http.Error(w, "缺少用户ID参数", http.StatusBadRequest) log.Printf("请求路径 %s 缺少user_id参数", r.URL.Path) return } userID, err := strconv.Atoi(userIDStr) if err != nil { http.Error(w, "无效的用户ID格式", http.StatusBadRequest) log.Printf("解析用户ID失败: %v, 请求路径: %s", err, r.URL.Path) return } // 查询用户信息 user, err := GetUserByID(userID) if err != nil { // 判断是否为用户不存在的错误 if errors.Is(err, sql.ErrNoRows) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) json.NewEncoder(w).Encode(map[string]string{ "error": "指定的用户不存在", }) log.Printf("用户ID %d 不存在, 请求路径: %s", userID, r.URL.Path) return } // 其他数据库错误,返回500 http.Error(w, "服务器内部错误", http.StatusInternalServerError) log.Printf("查询用户ID %d 失败: %v", userID, err) return } // 用户存在,返回用户详情 w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(user) }
2. 数据库查询函数
type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` } var db *sql.DB // 假设已初始化数据库连接 func GetUserByID(userID int) (*User, error) { var user User query := "SELECT id, name, email FROM users WHERE id = ?" err := db.QueryRow(query, userID).Scan(&user.ID, &user.Name, &user.Email) if err != nil { return nil, err } return &user, nil }
进阶优化建议
- 自定义错误类型:可以封装专属的「用户不存在」错误,让代码语义更清晰:
之后在handler里直接判断var ErrUserNotFound = errors.New("用户不存在") func GetUserByID(userID int) (*User, error) { var user User query := "SELECT id, name, email FROM users WHERE id = ?" err := db.QueryRow(query, userID).Scan(&user.ID, &user.Name, &user.Email) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrUserNotFound } return nil, err } return &user, nil }errors.Is(err, ErrUserNotFound)即可。 - 统一错误处理:将重复的错误逻辑抽成公共函数,减少代码冗余:
调用时只需:func handleUserQueryError(w http.ResponseWriter, r *http.Request, err error, userID int) bool { if errors.Is(err, ErrUserNotFound) || errors.Is(err, sql.ErrNoRows) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) json.NewEncoder(w).Encode(map[string]string{"error": "指定的用户不存在"}) log.Printf("用户ID %d 不存在", userID) return true } if err != nil { http.Error(w, "服务器内部错误", http.StatusInternalServerError) log.Printf("查询用户失败: %v, 用户ID: %d", err, userID) return true } return false }user, err := GetUserByID(userID) if handleUserQueryError(w, r, err, userID) { return }
内容的提问来源于stack exchange,提问作者Jyothish B Chandran
相关产品推荐
相关产品推荐

