codecamp

案例5:Go 基础——实现简单的HTTP接口(新手友好)

案例5:Go 基础——实现简单的HTTP接口(新手友好)

需求描述

用Go语言实现一个简单的HTTP接口服务,包含3个核心接口:GET请求获取所有用户信息、GET请求根据ID获取单个用户信息、POST请求添加新用户,要求使用Go原生net/http包(无需额外依赖),代码结构清晰,附带详细注释,可直接运行,返回JSON格式响应,处理请求参数错误、用户ID不存在等异常情况,同时添加接口访问日志,方便调试。

Claude 输入

“用Go语言实现一个简单的HTTP接口服务,需求如下:

  1. 使用Go原生net/http包,无需额外依赖;
  2. 包含3个接口:GET /users(获取所有用户信息)、GET /users/{id}(根据ID获取单个用户)、POST /users(添加新用户,请求体为JSON格式,包含name和age字段);3. 所有接口返回JSON格式响应,成功返回200状态码,异常返回对应错误状态码(如400、404);
  3. 处理异常:请求参数错误、用户ID不存在、POST请求体解析失败、请求方法错误;
  4. 添加接口访问日志,打印请求方法、请求路径、访问时间;
  5. 代码结构清晰,附带详细注释,可直接运行;
  6. 用切片模拟数据库存储用户信息,用户包含id(int)、name(string)、age(int)字段。”

生成代码(参考)

package main


import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "strconv"
    "time"
)


// User 定义用户结构体,对应JSON格式
type User struct {
    ID   int    `json:"id"`   // 用户ID,唯一标识
    Name string `json:"name"` // 用户名
    Age  int    `json:"age"`  // 用户年龄
}


// 模拟数据库,用切片存储用户信息(实际开发中替换为真实数据库)
var users = []User{
    {ID: 1, Name: "张三", Age: 20},
    {ID: 2, Name: "李四", Age: 22},
    {ID: 3, Name: "王五", Age: 21},
}


// 全局变量,用于生成新用户的ID(模拟自增主键)
var nextUserID = 4


// 日志中间件:记录接口访问信息(请求方法、路径、访问时间)
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 记录访问时间、请求方法、请求路径
        log.Printf("[%s] %s %s", time.Now().Format("2006-01-02 15:04:05"), r.Method, r.URL.Path)
        // 调用下一个处理器(实际接口逻辑)
        next.ServeHTTP(w, r)
    })
}


// getAllUsersHandler 处理GET /users请求,返回所有用户信息
func getAllUsersHandler(w http.ResponseWriter, r *http.Request) {
    // 只允许GET方法,其他方法返回405 Method Not Allowed
    if r.Method != http.MethodGet {
        w.WriteHeader(http.StatusMethodNotAllowed)
        json.NewEncoder(w).Encode(map[string]string{"error": "只允许GET请求"})
        return
    }


    // 设置响应头为JSON格式
    w.Header().Set("Content-Type", "application/json")
    // 返回200状态码和所有用户信息
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(map[string]interface{}{
        "code": 200,
        "msg":  "success",
        "data": users,
    })
}


// getUserByIDHandler 处理GET /users/{id}请求,根据ID获取单个用户
func getUserByIDHandler(w http.ResponseWriter, r *http.Request) {
    // 只允许GET方法
    if r.Method != http.MethodGet {
        w.WriteHeader(http.StatusMethodNotAllowed)
        json.NewEncoder(w).Encode(map[string]string{"error": "只允许GET请求"})
        return
    }


    // 提取URL路径中的id参数(如/users/1,提取1)
    idStr := r.PathValue("id")
    // 将字符串id转换为int类型
    id, err := strconv.Atoi(idStr)
    if err != nil {
        // 转换失败,说明id不是有效数字,返回400 Bad Request
        w.WriteHeader(http.StatusBadRequest)
        json.NewEncoder(w).Encode(map[string]string{"error": "无效的用户ID,需输入数字"})
        return
    }


    // 遍历切片,查找对应ID的用户
    var targetUser User
    found := false
    for _, user := range users {
        if user.ID == id {
            targetUser = user
            found = true
            break
        }
    }


    // 若未找到用户,返回404 Not Found
    if !found {
        w.WriteHeader(http.StatusNotFound)
        json.NewEncoder(w).Encode(map[string]string{"error": "用户不存在"})
        return
    }


    // 找到用户,返回200状态码和用户信息
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(map[string]interface{}{
        "code": 200,
        "msg":  "success",
        "data": targetUser,
    })
}


// addUserHandler 处理POST /users请求,添加新用户
func addUserHandler(w http.ResponseWriter, r *http.Request) {
    // 只允许POST方法
    if r.Method != http.MethodPost {
        w.WriteHeader(http.StatusMethodNotAllowed)
        json.NewEncoder(w).Encode(map[string]string{"error": "只允许POST请求"})
        return
    }


    // 解析请求体(JSON格式),绑定到User结构体
    var newUser User
    err := json.NewDecoder(r.Body).Decode(&newUser)
    defer r.Body.Close() // 关闭请求体,避免资源泄漏
    if err != nil {
        // 解析失败,说明请求体格式错误,返回400 Bad Request
        w.WriteHeader(http.StatusBadRequest)
        json.NewEncoder(w).Encode(map[string]string{"error": "请求体格式错误,需为JSON格式,包含name和age字段"})
        return
    }


    // 验证请求参数:name不能为空,age需为正数
    if newUser.Name == "" || newUser.Age <= 0 {
        w.WriteHeader(http.StatusBadRequest)
        json.NewEncoder(w).Encode(map[string]string{"error": "参数错误:name不能为空,age需为正数"})
        return
    }


    // 给新用户分配ID(自增),添加到切片中
    newUser.ID = nextUserID
    users = append(users, newUser)
    nextUserID++ // ID自增,为下一个用户做准备


    // 返回200状态码和添加成功的用户信息
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    json.NewEncoder(w).Encode(map[string]interface{}{
        "code": 200,
        "msg":  "用户添加成功",
        "data": newUser,
    })
}


func main() {
    // 注册路由,绑定接口路径和对应的处理器
    // 使用日志中间件,所有请求都会先经过日志处理
    http.Handle("/users", loggingMiddleware(http.HandlerFunc(getAllUsersHandler)))
    // 路由参数:{id}表示动态ID,Go 1.22+支持PathValue提取
    http.Handle("/users/{id}", loggingMiddleware(http.HandlerFunc(getUserByIDHandler)))
    http.Handle("/users", loggingMiddleware(http.HandlerFunc(addUserHandler)))


    // 启动HTTP服务,监听8080端口
    log.Println("HTTP服务已启动,监听端口:8080")
    log.Println("可用接口:")
    log.Println("1. GET http://localhost:8080/users  —— 获取所有用户")
    log.Println("2. GET http://localhost:8080/users/1 —— 获取ID为1的用户")
    log.Println("3. POST http://localhost:8080/users —— 添加新用户(请求体JSON:{\"name\":\"xxx\",\"age\":xx})")


    // 启动服务,若失败则打印错误并退出
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatalf("服务启动失败:%v", err)
    }
}



效果测试与调整

  1. 将生成的代码复制到Go编辑器(如Goland、VS Code),保存为“main.go”文件;
  2. 打开终端,进入代码所在目录,执行命令“go run main.go”,启动HTTP服务,终端会显示服务启动信息及可用接口;
  3. 测试接口(可使用Postman、curl或浏览器):测试GET /users:浏览器访问“http://localhost:8080/users”,或curl命令“curl http://localhost:8080/users”,可看到所有用户的JSON响应
  4. 测试GET /users/{id}:访问“http://localhost:8080/users/1”,可获取ID为1的用户信息;若访问“http://localhost:8080/users/10”(不存在的ID),会返回404错误;若访问“http://localhost:8080/users/abc”(无效ID),会返回400错误
  5. 测试POST /users:使用Postman发送POST请求,地址“http://localhost:8080/users”,请求体为JSON格式(如{"name":"赵六","age":23}),请求头设置“Content-Type: application/json”,发送后会返回添加成功的响应,再次访问GET /users可看到新添加的用户;若请求体格式错误(如缺少age字段),会返回400错误。
  6. 异常测试:故意发送非GET/POST方法的请求(如PUT /users),会返回405错误;发送POST请求时,若age设为负数,会返回参数错误提示;
  7. 调整需求:若想添加“删除用户”接口,可回到Claude Code输入区,补充“给HTTP接口服务添加DELETE /users/{id}接口,根据ID删除用户,处理用户不存在、ID无效的异常,添加访问日志”,重新生成代码即可;若想使用gin框架(而非原生net/http包)实现,可补充“使用gin框架重写该HTTP接口服务,保留所有功能,代码附带注释”。
案例4:代码重构——简化冗长的Python代码
5. 进阶技巧:解锁 Claude Code 高效用法(突破瓶颈)
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }