第八章:项目实战 - 构建Web服务

作者:Administrator 发布时间: 2026-03-13 阅读量:1 评论数:0

第八章:项目实战 - 构建Web服务

8.1 使用net/http构建Web服务

基础HTTP服务

package main
​
import (
    "fmt"
    "net/http"
)
​
func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World!")
}
​
func main() {
    // 注册路由
    http.HandleFunc("/", helloHandler)
    http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "你好!")
    })
    
    // 启动服务
    fmt.Println("服务器启动在 :8080")
    http.ListenAndServe(":8080", nil)
}

处理不同HTTP方法

package main
​
import (
    "encoding/json"
    "fmt"
    "net/http"
)
​
type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}
​
var users = []User{
    {ID: 1, Name: "张三"},
    {ID: 2, Name: "李四"},
}
​
func usersHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        // 获取所有用户
        json.NewEncoder(w).Encode(users)
    case http.MethodPost:
        // 创建用户
        var user User
        json.NewDecoder(r.Body).Decode(&user)
        users = append(users, user)
        w.WriteHeader(http.StatusCreated)
        json.NewEncoder(w).Encode(user)
    default:
        w.WriteHeader(http.StatusMethodNotAllowed)
    }
}
​
func main() {
    http.HandleFunc("/users", usersHandler)
    fmt.Println("服务器启动在 :8080")
    http.ListenAndServe(":8080", nil)
}

8.2 使用Gin框架

安装Gin

go get -u github.com/gin-gonic/gin

基础使用

package main
​
import (
    "net/http"
    "github.com/gin-gonic/gin"
)
​
func main() {
    // 创建路由
    r := gin.Default()
    
    // GET请求
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "pong",
        })
    })
    
    // 带参数
    r.GET("/user/:name", func(c *gin.Context) {
        name := c.Param("name")
        c.JSON(http.StatusOK, gin.H{
            "name": name,
        })
    })
    
    // 查询参数
    r.GET("/welcome", func(c *gin.Context) {
        firstname := c.DefaultQuery("firstname", "Guest")
        lastname := c.Query("lastname")
        c.JSON(http.StatusOK, gin.H{
            "firstname": firstname,
            "lastname":  lastname,
        })
    })
    
    // POST + JSON
    r.POST("/login", func(c *gin.Context) {
        var json struct {
            User     string `json:"user" binding:"required"`
            Password string `json:"password" binding:"required"`
        }
        
        if err := c.ShouldBindJSON(&json); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        
        c.JSON(http.StatusOK, gin.H{
            "status": "登录成功",
            "user":   json.User,
        })
    })
    
    // 表单
    r.POST("/form", func(c *gin.Context) {
        message := c.PostForm("message")
        nick := c.DefaultPostForm("nick", "anonymous")
        c.JSON(http.StatusOK, gin.H{
            "message": message,
            "nick":    nick,
        })
    })
    
    // 上传文件
    r.POST("/upload", func(c *gin.Context) {
        file, _ := c.FormFile("file")
        c.SaveUploadedFile(file, "/tmp/"+file.Filename)
        c.JSON(http.StatusOK, gin.H{
            "filename": file.Filename,
        })
    })
    
    r.Run()  // 默认在 :8080
}

路由组与中间件

package main
​
import (
    "net/http"
    "time"
    "github.com/gin-gonic/gin"
)
​
func main() {
    r := gin.New()
    
    // 全局中间件
    r.Use(gin.Logger())
    r.Use(gin.Recovery())
    
    // 自定义中间件
    r.Use(func(c *gin.Context) {
        start := time.Now()
        c.Next()  // 执行后续处理
        duration := time.Since(start)
        fmt.Printf("请求耗时: %v\n", duration)
    })
    
    // 路由组
    api := r.Group("/api")
    {
        // 需要认证的组
        authorized := api.Group("/")
        authorized.Use(AuthMiddleware())
        {
            authorized.GET("/users", getUsers)
            authorized.POST("/users", createUser)
        }
        
        // 公开API
        api.GET("/public", publicHandler)
    }
    
    r.Run()
}
​
func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
                "error": "未授权",
            })
            return
        }
        c.Next()
    }
}
​
func getUsers(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"users": []string{"张三", "李四"}})
}
​
func createUser(c *gin.Context) {
    c.JSON(http.StatusCreated, gin.H{"message": "用户创建成功"})
}
​
func publicHandler(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"message": "公开信息"})
}

8.3 项目实战:RESTful API

package main
​
import (
    "net/http"
    "strconv"
    "github.com/gin-gonic/gin"
)
​
// 任务模型
type Task struct {
    ID          int    `json:"id"`
    Title       string `json:"title" binding:"required"`
    Description string `json:"description"`
    Status      string `json:"status"`
}
​
// 内存存储
type TaskStore struct {
    tasks  []Task
    nextID int
}
​
func NewTaskStore() *TaskStore {
    return &TaskStore{
        tasks:  []Task{},
        nextID: 1,
    }
}
​
func (s *TaskStore) GetAll() []Task {
    return s.tasks
}
​
func (s *TaskStore) GetByID(id int) *Task {
    for _, t := range s.tasks {
        if t.ID == id {
            return &t
        }
    }
    return nil
}
​
func (s *TaskStore) Create(task Task) Task {
    task.ID = s.nextID
    task.Status = "pending"
    s.nextID++
    s.tasks = append(s.tasks, task)
    return task
}
​
func (s *TaskStore) Update(id int, updated Task) *Task {
    for i, t := range s.tasks {
        if t.ID == id {
            s.tasks[i].Title = updated.Title
            s.tasks[i].Description = updated.Description
            s.tasks[i].Status = updated.Status
            return &s.tasks[i]
        }
    }
    return nil
}
​
func (s *TaskStore) Delete(id int) bool {
    for i, t := range s.tasks {
        if t.ID == id {
            s.tasks = append(s.tasks[:i], s.tasks[i+1:]...)
            return true
        }
    }
    return false
}
​
var store = NewTaskStore()
​
func main() {
    r := gin.Default()
    
    // 初始化一些数据
    store.Create(Task{Title: "学习Go语言", Description: "完成基础教程"})
    store.Create(Task{Title: "构建Web服务", Description: "使用Gin框架"})
    
    // API路由
    api := r.Group("/api/v1")
    {
        api.GET("/tasks", getTasks)
        api.GET("/tasks/:id", getTask)
        api.POST("/tasks", createTask)
        api.PUT("/tasks/:id", updateTask)
        api.DELETE("/tasks/:id", deleteTask)
    }
    
    r.Run(":8080")
}
​
func getTasks(c *gin.Context) {
    tasks := store.GetAll()
    c.JSON(http.StatusOK, gin.H{
        "data": tasks,
    })
}
​
func getTask(c *gin.Context) {
    id, err := strconv.Atoi(c.Param("id"))
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "无效ID"})
        return
    }
    
    task := store.GetByID(id)
    if task == nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "任务不存在"})
        return
    }
    
    c.JSON(http.StatusOK, gin.H{"data": task})
}
​
func createTask(c *gin.Context) {
    var task Task
    if err := c.ShouldBindJSON(&task); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    
    created := store.Create(task)
    c.JSON(http.StatusCreated, gin.H{"data": created})
}
​
func updateTask(c *gin.Context) {
    id, err := strconv.Atoi(c.Param("id"))
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "无效ID


评论