Go HTTP
Go 语言在标准库 net/http 包中提供了完整的 HTTP 客户端和服务器实现。Go 的 HTTP 包设计简洁高效,非常适合构建 Web 服务、API 服务器和微服务。
下面是一个示例:
package main
import (
"encoding/json"
"fmt"
"html/template"
"io"
"log"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
)
// 1. 基本 HTTP 服务器
func basicHTTPServer() {
fmt.Println("=== 基本 HTTP 服务器 ===")
// 基本路由处理
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `
<h1>Go HTTP 服务器</h1>
<ul>
<li><a href="/hello">Hello</a></li>
<li><a href="/time">当前时间</a></li>
<li><a href="/api/users">用户 API</a></li>
<li><a href="/form">表单示例</a></li>
</ul>
`)
})
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
name = "World"
}
fmt.Fprintf(w, "<h1>Hello, %s!</h1>", name)
})
http.HandleFunc("/time", func(w http.ResponseWriter, r *http.Request) {
currentTime := time.Now().Format("2006-01-02 15:04:05")
fmt.Fprintf(w, "当前时间: %s", currentTime)
})
// 启动服务器
port := ":8080"
fmt.Printf("服务器启动在 http://localhost%s\n", port)
log.Fatal(http.ListenAndServe(port, nil))
}
// 2. RESTful API 服务器
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreateAt string `json:"create_at"`
}
type UserStore struct {
users map[int]User
mu sync.RWMutex
nextID int
}
func NewUserStore() *UserStore {
return &UserStore{
users: make(map[int]User),
nextID: 1,
}
}
func (s *UserStore) CreateUser(user User) User {
s.mu.Lock()
defer s.mu.Unlock()
user.ID = s.nextID
user.CreateAt = time.Now().Format(time.RFC3339)
s.users[user.ID] = user
s.nextID++
return user
}
func (s *UserStore) GetUser(id int) (User, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
user, exists := s.users[id]
return user, exists
}
func (s *UserStore) GetAllUsers() []User {
s.mu.RLock()
defer s.mu.RUnlock()
users := make([]User, 0, len(s.users))
for _, user := range s.users {
users = append(users, user)
}
return users
}
func (s *UserStore) UpdateUser(id int, updated User) (User, bool) {
s.mu.Lock()
defer s.mu.Unlock()
if _, exists := s.users[id]; !exists {
return User{}, false
}
updated.ID = id
updated.CreateAt = s.users[id].CreateAt
s.users[id] = updated
return updated, true
}
func (s *UserStore) DeleteUser(id int) bool {
s.mu.Lock()
defer s.mu.Unlock()
if _, exists := s.users[id]; !exists {
return false
}
delete(s.users, id)
return true
}
type APIServer struct {
store *UserStore
}
func NewAPIServer() *APIServer {
return &APIServer{
store: NewUserStore(),
}
}
func (s *APIServer) Start(port string) {
mux := http.NewServeMux()
// 用户 API 路由
mux.HandleFunc("GET /api/users", s.getUsers)
mux.HandleFunc("GET /api/users/{id}", s.getUser)
mux.HandleFunc("POST /api/users", s.createUser)
mux.HandleFunc("PUT /api/users/{id}", s.updateUser)
mux.HandleFunc("DELETE /api/users/{id}", s.deleteUser)
// 健康检查
mux.HandleFunc("GET /health", s.healthCheck)
// 静态文件服务
mux.Handle("/static/", http.StripPrefix("/static/",
http.FileServer(http.Dir("./static"))))
// 添加中间件
handler := s.loggingMiddleware(s.jsonMiddleware(mux))
fmt.Printf("REST API 服务器启动在 http://localhost%s\n", port)
log.Fatal(http.ListenAndServe(port, handler))
}
func (s *APIServer) 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 %v", r.Method, r.URL.Path, time.Since(start))
})
}
func (s *APIServer) jsonMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
next.ServeHTTP(w, r)
})
}
func (s *APIServer) healthCheck(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{
"status": "healthy",
"timestamp": time.Now().Format(time.RFC3339),
})
}
func (s *APIServer) getUsers(w http.ResponseWriter, r *http.Request) {
users := s.store.GetAllUsers()
json.NewEncoder(w).Encode(users)
}
func (s *APIServer) getUser(w http.ResponseWriter, r *http.Request) {
idStr := strings.TrimPrefix(r.URL.Path, "/api/users/")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, `{"error": "Invalid user ID"}`, http.StatusBadRequest)
return
}
user, exists := s.store.GetUser(id)
if !exists {
http.Error(w, `{"error": "User not found"}`, http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(user)
}
func (s *APIServer) createUser(w http.ResponseWriter, r *http.Request) {
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, `{"error": "Invalid JSON"}`, http.StatusBadRequest)
return
}
if user.Name == "" || user.Email == "" {
http.Error(w, `{"error": "Name and email are required"}`, http.StatusBadRequest)
return
}
created := s.store.CreateUser(user)
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(created)
}
func (s *APIServer) updateUser(w http.ResponseWriter, r *http.Request) {
idStr := strings.TrimPrefix(r.URL.Path, "/api/users/")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, `{"error": "Invalid user ID"}`, http.StatusBadRequest)
return
}
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, `{"error": "Invalid JSON"}`, http.StatusBadRequest)
return
}
updated, exists := s.store.UpdateUser(id, user)
if !exists {
http.Error(w, `{"error": "User not found"}`, http.StatusNotFound)
return
}
json.NewEncoder(w).Encode(updated)
}
func (s *APIServer) deleteUser(w http.ResponseWriter, r *http.Request) {
idStr := strings.TrimPrefix(r.URL.Path, "/api/users/")
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, `{"error": "Invalid user ID"}`, http.StatusBadRequest)
return
}
if !s.store.DeleteUser(id) {
http.Error(w, `{"error": "User not found"}`, http.StatusNotFound)
return
}
w.WriteHeader(http.StatusNoContent)
}
// 3. 模板渲染示例
type PageData struct {
Title string
Users []User
Time string
}
func templateServer() {
fmt.Println("=== 模板服务器 ===")
// 创建模板
tmpl := template.Must(template.New("").Parse(`
<!DOCTYPE html>
<html>
<head>
<title>{{.Title}}</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.user { border: 1px solid #ddd; padding: 10px; margin: 10px 0; }
.time { color: #666; font-size: 0.9em; }
</style>
</head>
<body>
<h1>{{.Title}}</h1>
<div class="time">服务器时间: {{.Time}}</div>
<h2>用户列表</h2>
{{range .Users}}
<div class="user">
<strong>{{.Name}}</strong> (ID: {{.ID}})<br>
Email: {{.Email}}<br>
创建时间: {{.CreateAt}}
</div>
{{else}}
<p>暂无用户</p>
{{end}}
</body>
</html>
`))
store := NewUserStore()
// 添加示例数据
store.CreateUser(User{Name: "张三", Email: "zhang@example.com"})
store.CreateUser(User{Name: "李四", Email: "li@example.com"})
http.HandleFunc("/template", func(w http.ResponseWriter, r *http.Request) {
data := PageData{
Title: "Go 模板示例",
Users: store.GetAllUsers(),
Time: time.Now().Format("2006-01-02 15:04:05"),
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := tmpl.Execute(w, data); err != nil {
http.Error(w, "模板渲染错误", http.StatusInternalServerError)
}
})
port := ":8081"
fmt.Printf("模板服务器启动在 http://localhost%s/template\n", port)
log.Fatal(http.ListenAndServe(port, nil))
}
// 4. 文件上传示例
func uploadServer() {
fmt.Println("=== 文件上传服务器 ===")
// 创建上传目录
os.MkdirAll("uploads", 0755)
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
// 显示上传表单
fmt.Fprint(w, `
<!DOCTYPE html>
<html>
<head><title>文件上传</title></head>
<body>
<h1>文件上传示例</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" multiple>
<button type="submit">上传</button>
</form>
</body>
</html>
`)
return
}
if r.Method == "POST" {
// 解析多部分表单
err := r.ParseMultipartForm(10 << 20) // 10MB
if err != nil {
http.Error(w, "文件太大", http.StatusBadRequest)
return
}
files := r.MultipartForm.File["file"]
var results []string
for _, fileHeader := range files {
result, err := handleUpload(fileHeader)
if err != nil {
results = append(results, fmt.Sprintf("错误: %s - %v", fileHeader.Filename, err))
} else {
results = append(results, result)
}
}
w.Header().Set("Content-Type", "text/html")
fmt.Fprintf(w, "<h1>上传结果</h1><ul>")
for _, result := range results {
fmt.Fprintf(w, "<li>%s</li>", result)
}
fmt.Fprint(w, "</ul><a href='/upload'>继续上传</a>")
}
})
// 文件下载
http.HandleFunc("/download/", func(w http.ResponseWriter, r *http.Request) {
filename := strings.TrimPrefix(r.URL.Path, "/download/")
filepath := filepath.Join("uploads", filename)
// 安全检查
if strings.Contains(filename, "..") {
http.Error(w, "非法文件名", http.StatusBadRequest)
return
}
w.Header().Set("Content-Disposition", "attachment; filename="+filename)
http.ServeFile(w, r, filepath)
})
port := ":8082"
fmt.Printf("文件服务器启动在 http://localhost%s/upload\n", port)
log.Fatal(http.ListenAndServe(port, nil))
}
func handleUpload(fileHeader *multipart.FileHeader) (string, error) {
file, err := fileHeader.Open()
if err != nil {
return "", err
}
defer file.Close()
// 创建目标文件
dstPath := filepath.Join("uploads", fileHeader.Filename)
dst, err := os.Create(dstPath)
if err != nil {
return "", err
}
defer dst.Close()
// 复制文件内容
if _, err := io.Copy(dst, file); err != nil {
return "", err
}
return fmt.Sprintf("文件上传成功: %s (大小: %d bytes)",
fileHeader.Filename, fileHeader.Size), nil
}
// 5. HTTP 客户端示例
func httpClientExamples() {
fmt.Println("=== HTTP 客户端示例 ===")
// 1. GET 请求
fmt.Println("\n1. GET 请求示例:")
resp, err := http.Get("https://httpbin.org/get")
if err != nil {
log.Printf("GET 请求失败: %v", err)
} else {
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("状态码: %d\n", resp.StatusCode)
fmt.Printf("响应头: %v\n", resp.Header)
fmt.Printf("响应体: %s\n", string(body[:100])) // 只显示前100字符
}
// 2. POST 请求 (JSON)
fmt.Println("\n2. POST 请求示例:")
data := map[string]string{"name": "Go HTTP Client", "value": "test"}
jsonData, _ := json.Marshal(data)
resp, err = http.Post("https://httpbin.org/post", "application/json", strings.NewReader(string(jsonData)))
if err != nil {
log.Printf("POST 请求失败: %v", err)
} else {
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("状态码: %d\n", resp.StatusCode)
fmt.Printf("响应: %s\n", string(body[:200]))
}
// 3. 自定义请求
fmt.Println("\n3. 自定义请求示例:")
client := &http.Client{
Timeout: 10 * time.Second,
}
req, err := http.NewRequest("GET", "https://httpbin.org/headers", nil)
if err != nil {
log.Printf("创建请求失败: %v", err)
return
}
req.Header.Set("User-Agent", "Go-HTTP-Client/1.0")
req.Header.Set("Authorization", "Bearer fake-token")
resp, err = client.Do(req)
if err != nil {
log.Printf("请求执行失败: %v", err)
return
}
defer resp.Body.Close()
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
log.Printf("JSON 解析失败: %v", err)
return
}
fmt.Printf("自定义头信息: %v\n", result["headers"])
}
// 6. 中间件链示例
type Middleware func(http.HandlerFunc) http.HandlerFunc
func ChainMiddleware(h http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
for i := len(middlewares) - 1; i >= 0; i-- {
h = middlewares[i](h)
}
return h
}
func LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("开始处理 %s %s", r.Method, r.URL.Path)
// 创建自定义 ResponseWriter 来捕获状态码
rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
next(rw, r)
log.Printf("完成处理 %s %s - 状态码: %d, 耗时: %v",
r.Method, r.URL.Path, rw.statusCode, time.Since(start))
}
}
func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token != "Bearer secret-token" {
http.Error(w, `{"error": "未授权"}`, http.StatusUnauthorized)
return
}
next(w, r)
}
}
type responseWriter struct {
http.ResponseWriter
statusCode int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
func middlewareExample() {
fmt.Println("=== 中间件示例 ===")
protectedHandler := func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"message": "这是受保护的内容",
"user": "认证用户",
})
}
// 应用中间件链
handler := ChainMiddleware(protectedHandler, LoggingMiddleware, AuthMiddleware)
http.HandleFunc("/protected", handler)
port := ":8083"
fmt.Printf("中间件示例启动在 http://localhost%s/protected\n", port)
fmt.Println("使用 Header: Authorization: Bearer secret-token")
log.Fatal(http.ListenAndServe(port, nil))
}
func main() {
if len(os.Args) < 2 {
fmt.Println("HTTP 示例用法:")
fmt.Println(" 基本服务器: go run http.go basic")
fmt.Println(" API服务器: go run http.go api")
fmt.Println(" 模板服务器: go run http.go template")
fmt.Println(" 文件服务器: go run http.go upload")
fmt.Println(" 客户端示例: go run http.go client")
fmt.Println(" 中间件示例: go run http.go middleware")
return
}
mode := os.Args[1]
switch mode {
case "basic":
basicHTTPServer()
case "api":
server := NewAPIServer()
server.Start(":8080")
case "template":
templateServer()
case "upload":
uploadServer()
case "client":
httpClientExamples()
case "middleware":
middlewareExample()
default:
fmt.Println("未知模式")
}
}
HTTP 编程关键要点
- 核心组件
处理器 (Handler):实现 ServeHTTP 方法
多路复用器 (Mux):路由请求到处理器
响应编写器 (ResponseWriter):构建 HTTP 响应
请求 (Request):包含请求信息
- 重要特性
并发安全 :每个请求在独立 goroutine 中处理
中间件支持 :灵活的请求处理管道
自动路由 :支持模式匹配和参数提取
HTTPS 支持 :内置 TLS/SSL 支持
- 最佳实践
使用中间件 :日志、认证、限流等
错误处理 :适当的 HTTP 状态码和错误信息
超时控制 :设置合理的读写超时
资源清理 :及时关闭响应体
安全考虑 :输入验证、CORS、CSRF 防护
Go 的 HTTP 包功能强大且易于使用,是构建 Web 服务和 API 的理想选择。
通关密语:http