项目概述
技术栈
- Web框架:Gin(高性能HTTP框架)
- 数据存储:Redis(内存数据库,用于高并发读写)
项目结构
bash
coach-booking-service
├── main.go # 程序入口,路由初始化,服务启动
├── handlers # HTTP请求处理层
│ └── booking.go
├── services # 业务逻辑层
│ └── booking.go
├── repositories # 数据访问层
│ └── redis_repo.go
├── models # 数据模型定义
│ └── models.go
Gin框架核心实践
1. 路由配置(main.go)
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. 安全中间件实现
go
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)
go
func (h *BookingHandler) BookCoach(c *gin.Context) {
// 参数绑定与验证
var req models.BookingRequest
if 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)
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 := 9
slotIndex := 4 - position
startTime := startHour + (slotIndex * 90 / 60)
startMinute := (slotIndex * 90) % 60
scheduledTime := fmt.Sprintf("%02d:%02d", startTime, startMinute)
return models.BookingResponse{
Success: true,
Message: "预约成功",
ScheduledTime: scheduledTime,
Position: position,
}
}
Service层职责:
- 实现核心业务逻辑
- 调用Repository层进行数据访问
- 处理业务异常
- 数据转换和封装
数据访问层实现(repositories/redis_repo.go)
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客户端也内置连接池管理:
go
rdb := redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
PoolSize: 100, // 连接池大小
MinIdleConns: 10, // 最小空闲连接
})
3. 超时控制
在HTTP服务器层设置超时参数,防止慢速攻击:
go
server := &http.Server{
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
IdleTimeout: 60 * time.Second,
}
使用Nginx作为反向代理,处理HTTPS和静态文件
编辑配置文件
bash
sudo nvim /etc/nginx/sites-available/myself_server.com
添加配置文件
启用配置并重启nginx
bash
sudo ln -s /etc/nginx/sites-available/myself_server.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx