<返回目录     Powered by claud/xia兄

第13课: Web开发与HTTP服务

net/http包基础

Go标准库的net/http包提供了完整的HTTP客户端和服务器实现。

简单的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)

    fmt.Println("服务器启动在 http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

处理不同的HTTP方法

func userHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        fmt.Fprintf(w, "GET请求")
    case http.MethodPost:
        fmt.Fprintf(w, "POST请求")
    case http.MethodPut:
        fmt.Fprintf(w, "PUT请求")
    case http.MethodDelete:
        fmt.Fprintf(w, "DELETE请求")
    default:
        http.Error(w, "方法不允许", http.StatusMethodNotAllowed)
    }
}

路由和多路复用器

使用http.ServeMux

package main

import (
    "fmt"
    "net/http"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/", homeHandler)
    mux.HandleFunc("/about", aboutHandler)
    mux.HandleFunc("/api/users", usersHandler)

    http.ListenAndServe(":8080", mux)
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "首页")
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "关于页面")
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "用户列表")
}

处理请求和响应

读取请求参数

func searchHandler(w http.ResponseWriter, r *http.Request) {
    // 查询参数
    query := r.URL.Query()
    keyword := query.Get("q")
    page := query.Get("page")

    fmt.Fprintf(w, "搜索: %s, 页码: %s", keyword, page)
}

// 访问: http://localhost:8080/search?q=golang&page=1

读取POST数据

func loginHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "只支持POST", http.StatusMethodNotAllowed)
        return
    }

    // 解析表单数据
    r.ParseForm()
    username := r.FormValue("username")
    password := r.FormValue("password")

    fmt.Fprintf(w, "用户名: %s", username)
}

处理JSON

package main

import (
    "encoding/json"
    "net/http"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
    Email string `json:"email"`
}

func getUserHandler(w http.ResponseWriter, r *http.Request) {
    user := User{
        ID:   1,
        Name: "Alice",
        Email: "alice@example.com",
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}

func createUserHandler(w http.ResponseWriter, r *http.Request) {
    var user User

    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // 处理用户创建逻辑
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(user)
}

中间件

中间件是处理HTTP请求的函数链,用于日志、认证、CORS等。

基本中间件

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Printf("%s %s\n", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
    })
}

func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if token == "" {
            http.Error(w, "未授权", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/api/users", usersHandler)

    // 应用中间件
    handler := loggingMiddleware(authMiddleware(mux))
    http.ListenAndServe(":8080", handler)
}

RESTful API示例

package main

import (
    "encoding/json"
    "net/http"
    "strconv"
    "strings"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

var users = []User{
    {ID: 1, Name: "Alice"},
    {ID: 2, Name: "Bob"},
}

func usersHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        // GET /api/users - 获取所有用户
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(users)

    case http.MethodPost:
        // POST /api/users - 创建用户
        var user User
        if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
        user.ID = len(users) + 1
        users = append(users, user)

        w.WriteHeader(http.StatusCreated)
        json.NewEncoder(w).Encode(user)

    default:
        http.Error(w, "方法不允许", http.StatusMethodNotAllowed)
    }
}

func userHandler(w http.ResponseWriter, r *http.Request) {
    // 提取ID: /api/users/1
    parts := strings.Split(r.URL.Path, "/")
    if len(parts) < 4 {
        http.Error(w, "无效的URL", http.StatusBadRequest)
        return
    }

    id, err := strconv.Atoi(parts[3])
    if err != nil {
        http.Error(w, "无效的ID", http.StatusBadRequest)
        return
    }

    switch r.Method {
    case http.MethodGet:
        // GET /api/users/:id - 获取单个用户
        for _, user := range users {
            if user.ID == id {
                w.Header().Set("Content-Type", "application/json")
                json.NewEncoder(w).Encode(user)
                return
            }
        }
        http.Error(w, "用户未找到", http.StatusNotFound)

    case http.MethodPut:
        // PUT /api/users/:id - 更新用户
        var updatedUser User
        if err := json.NewDecoder(r.Body).Decode(&updatedUser); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }

        for i, user := range users {
            if user.ID == id {
                users[i].Name = updatedUser.Name
                json.NewEncoder(w).Encode(users[i])
                return
            }
        }
        http.Error(w, "用户未找到", http.StatusNotFound)

    case http.MethodDelete:
        // DELETE /api/users/:id - 删除用户
        for i, user := range users {
            if user.ID == id {
                users = append(users[:i], users[i+1:]...)
                w.WriteHeader(http.StatusNoContent)
                return
            }
        }
        http.Error(w, "用户未找到", http.StatusNotFound)

    default:
        http.Error(w, "方法不允许", http.StatusMethodNotAllowed)
    }
}

func main() {
    http.HandleFunc("/api/users", usersHandler)
    http.HandleFunc("/api/users/", userHandler)

    fmt.Println("服务器启动在 http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

Gin框架

Gin是一个高性能的Web框架,提供了更简洁的API和更多功能。

安装Gin

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

基本使用

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func main() {
    r := gin.Default()

    r.GET("/", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "Hello, Gin!",
        })
    })

    r.GET("/users/:id", func(c *gin.Context) {
        id := c.Param("id")
        c.JSON(http.StatusOK, gin.H{
            "user_id": id,
        })
    })

    r.POST("/users", func(c *gin.Context) {
        var user User
        if err := c.ShouldBindJSON(&user); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        c.JSON(http.StatusCreated, user)
    })

    r.Run(":8080")
}

Gin中间件

func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        fmt.Printf("%s %s\n", c.Request.Method, c.Request.URL.Path)
        c.Next()
    }
}

func Auth() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "未授权"})
            c.Abort()
            return
        }
        c.Next()
    }
}

func main() {
    r := gin.New()
    r.Use(Logger())

    api := r.Group("/api")
    api.Use(Auth())
    {
        api.GET("/users", getUsers)
        api.POST("/users", createUser)
    }

    r.Run(":8080")
}

最佳实践

常见错误:

实践练习

  1. 创建一个简单的HTTP服务器
  2. 实现完整的RESTful API
  3. 添加日志和认证中间件
  4. 使用Gin框架重写API
  5. 实现文件上传功能
  6. 添加CORS支持
  7. 实现请求限流
  8. 添加优雅关闭功能