You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
}

进阶优化建议

  • 自定义错误类型:可以封装专属的「用户不存在」错误,让代码语义更清晰:
    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
    }
    
    之后在handler里直接判断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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 13:20:15