Web开发

基本Web服务器

使用net/http包创建基本的Web服务器。

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}

func main() {
    // 注册处理函数
    http.HandleFunc("/", handler)
    
    // 启动服务器
    fmt.Println("Server starting on :8080...")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        panic(err)
    }
}

路由处理

使用gorilla/mux实现更强大的路由功能。

package main

import (
    "encoding/json"
    "net/http"
    "github.com/gorilla/mux"
)

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

var users = []User{
    {ID: "1", Name: "John"},
    {ID: "2", Name: "Jane"},
}

func getUsers(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(users)
}

func getUser(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    id := vars["id"]
    
    for _, user := range users {
        if user.ID == id {
            w.Header().Set("Content-Type", "application/json")
            json.NewEncoder(w).Encode(user)
            return
        }
    }
    
    w.WriteHeader(http.StatusNotFound)
}

func main() {
    r := mux.NewRouter()
    
    // 注册路由
    r.HandleFunc("/users", getUsers).Methods("GET")
    r.HandleFunc("/users/{id}", getUser).Methods("GET")
    
    // 启动服务器
    http.ListenAndServe(":8080", r)
}

中间件

使用中间件处理通用功能,如日志记录、认证等。

package main

import (
    "log"
    "net/http"
    "time"
)

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        
        // 调用下一个处理器
        next.ServeHTTP(w, r)
        
        // 记录请求信息
        log.Printf(
            "%s %s %s %v",
            r.Method,
            r.RequestURI,
            r.RemoteAddr,
            time.Since(start),
        )
    })
}

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, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        // 验证token
        if !isValidToken(token) {
            http.Error(w, "Invalid token", http.StatusUnauthorized)
            return
        }
        
        next.ServeHTTP(w, r)
    })
}

func main() {
    mux := http.NewServeMux()
    
    // 注册路由
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })
    
    // 使用中间件
    handler := loggingMiddleware(authMiddleware(mux))
    
    // 启动服务器
    http.ListenAndServe(":8080", handler)
}

模板渲染

使用html/template包渲染HTML模板。

package main

import (
    "html/template"
    "net/http"
)

type PageData struct {
    Title string
    Users []User
}

type User struct {
    Name  string
    Email string
}

func renderTemplate(w http.ResponseWriter, r *http.Request) {
    // 解析模板
    tmpl, err := template.ParseFiles("templates/layout.html", "templates/users.html")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    
    // 准备数据
    data := PageData{
        Title: "User List",
        Users: []User{
            {Name: "John", Email: "john@example.com"},
            {Name: "Jane", Email: "jane@example.com"},
        },
    }
    
    // 渲染模板
    if err := tmpl.Execute(w, data); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

func main() {
    http.HandleFunc("/", renderTemplate)
    http.ListenAndServe(":8080", nil)
}

静态文件服务

提供静态文件(如CSS、JavaScript、图片等)服务。

package main

import (
    "net/http"
)

func main() {
    // 创建文件服务器
    fs := http.FileServer(http.Dir("static"))
    
    // 注册静态文件路由
    http.Handle("/static/", http.StripPrefix("/static/", fs))
    
    // 注册其他路由
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })
    
    // 启动服务器
    http.ListenAndServe(":8080", nil)
}

表单处理

处理HTML表单提交的数据。

package main

import (
    "html/template"
    "net/http"
)

type User struct {
    Name     string
    Email    string
    Password string
}

func showForm(w http.ResponseWriter, r *http.Request) {
    tmpl := template.Must(template.ParseFiles("templates/form.html"))
    tmpl.Execute(w, nil)
}

func handleForm(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }
    
    // 解析表单数据
    if err := r.ParseForm(); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    // 获取表单字段
    user := User{
        Name:     r.FormValue("name"),
        Email:    r.FormValue("email"),
        Password: r.FormValue("password"),
    }
    
    // 处理用户数据...
    
    // 重定向到成功页面
    http.Redirect(w, r, "/success", http.StatusSeeOther)
}

func main() {
    http.HandleFunc("/", showForm)
    http.HandleFunc("/submit", handleForm)
    http.ListenAndServe(":8080", nil)
}

JSON处理

处理JSON数据的编码和解码。

package main

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

type Product struct {
    ID    string  `json:"id"`
    Name  string  `json:"name"`
    Price float64 `json:"price"`
}

func getProducts(w http.ResponseWriter, r *http.Request) {
    products := []Product{
        {ID: "1", Name: "Laptop", Price: 999.99},
        {ID: "2", Name: "Phone", Price: 499.99},
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(products)
}

func createProduct(w http.ResponseWriter, r *http.Request) {
    var product Product
    if err := json.NewDecoder(r.Body).Decode(&product); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    // 处理产品数据...
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(product)
}

func main() {
    http.HandleFunc("/products", func(w http.ResponseWriter, r *http.Request) {
        switch r.Method {
        case http.MethodGet:
            getProducts(w, r)
        case http.MethodPost:
            createProduct(w, r)
        default:
            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        }
    })
    
    http.ListenAndServe(":8080", nil)
}

错误处理

处理Web应用中的错误情况。

package main

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

type ErrorResponse struct {
    Error   string `json:"error"`
    Message string `json:"message"`
    Code    int    `json:"code"`
}

func handleError(w http.ResponseWriter, err error, status int) {
    response := ErrorResponse{
        Error:   http.StatusText(status),
        Message: err.Error(),
        Code:    status,
    }
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    json.NewEncoder(w).Encode(response)
}

func handler(w http.ResponseWriter, r *http.Request) {
    // 模拟错误情况
    if r.URL.Path == "/error" {
        handleError(w, fmt.Errorf("something went wrong"), http.StatusInternalServerError)
        return
    }
    
    if r.URL.Path == "/notfound" {
        handleError(w, fmt.Errorf("resource not found"), http.StatusNotFound)
        return
    }
    
    w.Write([]byte("OK"))
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}