項目概述
技術棧
- Web框架:Gin(高性能HTTP框架)
- 數據存儲:Redis(內存數據庫,用于高并發讀寫)
項目結構
coach-booking-service
├── main.go # 程序入口,路由初始化,服務啟動
├── handlers # HTTP請求處理層
│ └── booking.go
├── services # 業務邏輯層
│ └── booking.go
├── repositories # 數據訪問層
│ └── redis_repo.go
├── models # 數據模型定義
│ └── models.go
Gin框架核心實踐
1. 路由配置(main.go)
func main() {// 初始化依賴rdb := redis.NewClient(&redis.Options{...})repo := repositories.NewRedisRepository(rdb)bookingService := services.NewBookingService(repo)bookingHandler := handlers.NewBookingHandler(bookingService)// Gin生產環境配置gin.SetMode(gin.ReleaseMode)r := gin.New()// 安全中間件r.Use(gin.Recovery())r.Use(secureHeaders())// 信任代理配置trustedProxies := []string{"127.0.0.1"}r.SetTrustedProxies(trustedProxies)// 路由注冊r.POST("/book", bookingHandler.BookCoach)r.GET("/schedule/:coach_id/:date", bookingHandler.GetSchedule)r.GET("/health", healthCheck)// 安全HTTP服務器配置server := &http.Server{Addr: ":8080",Handler: r,ReadTimeout: 15 * time.Second,WriteTimeout: 15 * time.Second,IdleTimeout: 60 * time.Second,}server.ListenAndServe()
}
Gin最佳實踐:
- 使用gin.ReleaseMode減少日志輸出
- 自定義中間件而非使用gin.Default()的默認中間件
- 明確設置信任代理,防止X-Forwarded-For欺騙攻擊
- 配置HTTP服務器超時參數,防止慢速攻擊
2. 安全中間件實現
func secureHeaders() gin.HandlerFunc {return func(c *gin.Context) {// 設置安全相關的HTTP頭部c.Header("X-Frame-Options", "DENY")c.Header("X-Content-Type-Options", "nosniff")c.Header("X-XSS-Protection", "1; mode=block")c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")c.Header("Content-Security-Policy", "default-src 'self'")c.Next()}
}
安全頭部作用:
- X-Frame-Options:防止點擊劫持
- X-Content-Type-Options:阻止MIME類型嗅探
- X-XSS-Protection:啟用瀏覽器XSS過濾器
- Strict-Transport-Security:強制使用HTTPS
- Content-Security-Policy:限制資源加載來源
3. 請求處理(handlers/booking.go)
func (h *BookingHandler) BookCoach(c *gin.Context) {// 參數綁定與驗證var req models.BookingRequestif err := c.ShouldBindJSON(&req); err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})return}// 調用服務層response := h.service.BookCoach(req)c.JSON(http.StatusOK, response)
}func (h *BookingHandler) GetSchedule(c *gin.Context) {// 路徑參數獲取coachID := c.Param("coach_id")date := c.Param("date")// 調用服務層schedule, err := h.service.GetSchedule(coachID, date)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})return}c.JSON(http.StatusOK, schedule)
}
Handler層職責:
- 接收HTTP請求
- 參數綁定與驗證
- 調用Service層處理業務
- 返回HTTP響應
業務邏輯層設計(services/booking.go)
func (s *BookingService) BookCoach(req models.BookingRequest) models.BookingResponse {// 調用Repository層success, position, err := s.repo.BookCoach(ctx, req.CoachID, req.StudentID, req.Date)// 業務邏輯:計算預約時間startHour := 9slotIndex := 4 - positionstartTime := startHour + (slotIndex * 90 / 60)startMinute := (slotIndex * 90) % 60scheduledTime := fmt.Sprintf("%02d:%02d", startTime, startMinute)return models.BookingResponse{Success: true,Message: "預約成功",ScheduledTime: scheduledTime,Position: position,}
}
Service層職責:
- 實現核心業務邏輯
- 調用Repository層進行數據訪問
- 處理業務異常
- 數據轉換和封裝
數據訪問層實現(repositories/redis_repo.go)
func (r *RedisRepository) BookCoach(ctx context.Context, coachID, studentID, date string) (bool, int, error) {key := getScheduleKey(coachID, date)// 檢查是否已預約if member, _ := r.client.SIsMember(ctx, key+"_students", studentID).Result(); member {return false, 0, nil}// 檢查預約數量if count, _ := r.client.SCard(ctx, key+"_students").Result(); count >= 4 {return false, 0, nil}// 添加預約r.client.SAdd(ctx, key+"_students", studentID)// 添加到隊列position, _ := r.client.LPush(ctx, key, studentID).Result()return true, int(position), nil
}
Redis數據結構設計:
- List:存儲預約隊列(保證順序)
- Set:存儲已預約學員ID(快速查重)
鍵設計策略:
- 預約隊列鍵:
coach:{coachID}:date:{date}
- 學員集合鍵:
coach:{coachID}:date:{date}_students
高并發處理策略
1. Redis原子操作
使用Redis的SIsMember、SCard和LPush組合確保預約操作的原子性,避免并發沖突。
2. 連接池管理
Gin框架自動處理HTTP連接池,Redis客戶端也內置連接池管理:
rdb := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379",PoolSize: 100, // 連接池大小MinIdleConns: 10, // 最小空閑連接
})
3. 超時控制
在HTTP服務器層設置超時參數,防止慢速攻擊:
server := &http.Server{ReadTimeout: 15 * time.Second,WriteTimeout: 15 * time.Second,IdleTimeout: 60 * time.Second,
}
使用Nginx作為反向代理,處理HTTPS和靜態文件
編輯配置文件
sudo nvim /etc/nginx/sites-available/myself_server.com
添加配置文件
ngnix配置文件
啟用配置并重啟nginx
sudo ln -s /etc/nginx/sites-available/myself_server.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx