完成
This commit is contained in:
369
golang-learning/10-projects/03-web-server/server/handlers.go
Normal file
369
golang-learning/10-projects/03-web-server/server/handlers.go
Normal file
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
handlers.go - 请求处理器
|
||||
实现了各种HTTP请求的处理逻辑
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"webserver/models"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// Response 通用响应结构
|
||||
type Response struct {
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
}
|
||||
|
||||
// HealthResponse 健康检查响应
|
||||
type HealthResponse struct {
|
||||
Status string `json:"status"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Uptime string `json:"uptime"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// StatsResponse 统计信息响应
|
||||
type StatsResponse struct {
|
||||
Status string `json:"status"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Uptime string `json:"uptime"`
|
||||
Version string `json:"version"`
|
||||
GoVersion string `json:"go_version"`
|
||||
NumCPU int `json:"num_cpu"`
|
||||
NumGoroutine int `json:"num_goroutine"`
|
||||
MemStats runtime.MemStats `json:"mem_stats"`
|
||||
}
|
||||
|
||||
var (
|
||||
startTime = time.Now()
|
||||
version = "1.0.0"
|
||||
)
|
||||
|
||||
// HomeHandler 首页处理器
|
||||
func HomeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
html := `
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Go Web服务器</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 40px; background-color: #f5f5f5; }
|
||||
.container { max-width: 800px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
||||
h1 { color: #333; text-align: center; }
|
||||
.api-list { background: #f8f9fa; padding: 20px; border-radius: 5px; margin: 20px 0; }
|
||||
.api-item { margin: 10px 0; padding: 10px; background: white; border-left: 4px solid #007bff; }
|
||||
.method { font-weight: bold; color: #007bff; }
|
||||
.endpoint { font-family: monospace; background: #e9ecef; padding: 2px 6px; border-radius: 3px; }
|
||||
.description { color: #666; margin-top: 5px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🚀 Go Web服务器</h1>
|
||||
<p>欢迎使用Go语言编写的简单Web服务器!这个项目演示了HTTP服务器、RESTful API、JSON处理等功能。</p>
|
||||
|
||||
<h2>📚 API接口</h2>
|
||||
<div class="api-list">
|
||||
<div class="api-item">
|
||||
<span class="method">GET</span> <span class="endpoint">/health</span>
|
||||
<div class="description">健康检查</div>
|
||||
</div>
|
||||
<div class="api-item">
|
||||
<span class="method">GET</span> <span class="endpoint">/api/stats</span>
|
||||
<div class="description">服务器统计信息</div>
|
||||
</div>
|
||||
<div class="api-item">
|
||||
<span class="method">GET</span> <span class="endpoint">/api/users</span>
|
||||
<div class="description">获取所有用户</div>
|
||||
</div>
|
||||
<div class="api-item">
|
||||
<span class="method">POST</span> <span class="endpoint">/api/users</span>
|
||||
<div class="description">创建新用户</div>
|
||||
</div>
|
||||
<div class="api-item">
|
||||
<span class="method">GET</span> <span class="endpoint">/api/users/{id}</span>
|
||||
<div class="description">获取指定用户</div>
|
||||
</div>
|
||||
<div class="api-item">
|
||||
<span class="method">PUT</span> <span class="endpoint">/api/users/{id}</span>
|
||||
<div class="description">更新用户信息</div>
|
||||
</div>
|
||||
<div class="api-item">
|
||||
<span class="method">DELETE</span> <span class="endpoint">/api/users/{id}</span>
|
||||
<div class="description">删除用户</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>🛠️ 使用示例</h2>
|
||||
<pre style="background: #f8f9fa; padding: 15px; border-radius: 5px; overflow-x: auto;">
|
||||
# 获取所有用户
|
||||
curl http://localhost:8080/api/users
|
||||
|
||||
# 创建新用户
|
||||
curl -X POST http://localhost:8080/api/users \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"张三","email":"zhangsan@example.com","age":25}'
|
||||
|
||||
# 健康检查
|
||||
curl http://localhost:8080/health
|
||||
</pre>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(html))
|
||||
}
|
||||
|
||||
// HealthHandler 健康检查处理器
|
||||
func HealthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
uptime := time.Since(startTime)
|
||||
|
||||
response := HealthResponse{
|
||||
Status: "healthy",
|
||||
Timestamp: time.Now().Format(time.RFC3339),
|
||||
Uptime: uptime.String(),
|
||||
Version: version,
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
// StatsHandler 统计信息处理器
|
||||
func StatsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
uptime := time.Since(startTime)
|
||||
var memStats runtime.MemStats
|
||||
runtime.ReadMemStats(&memStats)
|
||||
|
||||
response := StatsResponse{
|
||||
Status: "success",
|
||||
Timestamp: time.Now().Format(time.RFC3339),
|
||||
Uptime: uptime.String(),
|
||||
Version: version,
|
||||
GoVersion: runtime.Version(),
|
||||
NumCPU: runtime.NumCPU(),
|
||||
NumGoroutine: runtime.NumGoroutine(),
|
||||
MemStats: memStats,
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
// GetUsersHandler 获取所有用户
|
||||
func GetUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||
users, err := models.GetAllUsers()
|
||||
if err != nil {
|
||||
sendErrorResponse(w, "获取用户列表失败", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response := Response{
|
||||
Status: "success",
|
||||
Data: users,
|
||||
Count: len(users),
|
||||
}
|
||||
|
||||
sendJSONResponse(w, response, http.StatusOK)
|
||||
}
|
||||
|
||||
// GetUserHandler 获取指定用户
|
||||
func GetUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
sendErrorResponse(w, "无效的用户ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := models.GetUserByID(id)
|
||||
if err != nil {
|
||||
sendErrorResponse(w, "用户不存在", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
response := Response{
|
||||
Status: "success",
|
||||
Data: user,
|
||||
}
|
||||
|
||||
sendJSONResponse(w, response, http.StatusOK)
|
||||
}
|
||||
|
||||
// CreateUserHandler 创建新用户
|
||||
func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var user models.User
|
||||
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
|
||||
sendErrorResponse(w, "无效的JSON数据", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证用户数据
|
||||
if err := user.Validate(); err != nil {
|
||||
sendErrorResponse(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
createdUser, err := models.CreateUser(user)
|
||||
if err != nil {
|
||||
sendErrorResponse(w, "创建用户失败", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response := Response{
|
||||
Status: "success",
|
||||
Message: "用户创建成功",
|
||||
Data: createdUser,
|
||||
}
|
||||
|
||||
sendJSONResponse(w, response, http.StatusCreated)
|
||||
}
|
||||
|
||||
// UpdateUserHandler 更新用户信息
|
||||
func UpdateUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
sendErrorResponse(w, "无效的用户ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
|
||||
sendErrorResponse(w, "无效的JSON数据", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置用户ID
|
||||
user.ID = id
|
||||
|
||||
// 验证用户数据
|
||||
if err := user.Validate(); err != nil {
|
||||
sendErrorResponse(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 更新用户
|
||||
updatedUser, err := models.UpdateUser(user)
|
||||
if err != nil {
|
||||
sendErrorResponse(w, "更新用户失败", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response := Response{
|
||||
Status: "success",
|
||||
Message: "用户更新成功",
|
||||
Data: updatedUser,
|
||||
}
|
||||
|
||||
sendJSONResponse(w, response, http.StatusOK)
|
||||
}
|
||||
|
||||
// DeleteUserHandler 删除用户
|
||||
func DeleteUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
sendErrorResponse(w, "无效的用户ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := models.DeleteUser(id); err != nil {
|
||||
sendErrorResponse(w, "删除用户失败", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response := Response{
|
||||
Status: "success",
|
||||
Message: "用户删除成功",
|
||||
}
|
||||
|
||||
sendJSONResponse(w, response, http.StatusOK)
|
||||
}
|
||||
|
||||
// APIDocHandler API文档处理器
|
||||
func APIDocHandler(w http.ResponseWriter, r *http.Request) {
|
||||
doc := map[string]interface{}{
|
||||
"title": "Go Web服务器 API",
|
||||
"version": version,
|
||||
"description": "一个简单的RESTful API服务器",
|
||||
"endpoints": map[string]interface{}{
|
||||
"health": map[string]string{
|
||||
"method": "GET",
|
||||
"path": "/health",
|
||||
"description": "健康检查",
|
||||
},
|
||||
"stats": map[string]string{
|
||||
"method": "GET",
|
||||
"path": "/api/stats",
|
||||
"description": "服务器统计信息",
|
||||
},
|
||||
"users": map[string]interface{}{
|
||||
"list": map[string]string{
|
||||
"method": "GET",
|
||||
"path": "/api/users",
|
||||
"description": "获取所有用户",
|
||||
},
|
||||
"get": map[string]string{
|
||||
"method": "GET",
|
||||
"path": "/api/users/{id}",
|
||||
"description": "获取指定用户",
|
||||
},
|
||||
"create": map[string]string{
|
||||
"method": "POST",
|
||||
"path": "/api/users",
|
||||
"description": "创建新用户",
|
||||
},
|
||||
"update": map[string]string{
|
||||
"method": "PUT",
|
||||
"path": "/api/users/{id}",
|
||||
"description": "更新用户信息",
|
||||
},
|
||||
"delete": map[string]string{
|
||||
"method": "DELETE",
|
||||
"path": "/api/users/{id}",
|
||||
"description": "删除用户",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
sendJSONResponse(w, doc, http.StatusOK)
|
||||
}
|
||||
|
||||
// sendJSONResponse 发送JSON响应
|
||||
func sendJSONResponse(w http.ResponseWriter, data interface{}, statusCode int) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(statusCode)
|
||||
if err := json.NewEncoder(w).Encode(data); err != nil {
|
||||
http.Error(w, "JSON编码失败", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
// sendErrorResponse 发送错误响应
|
||||
func sendErrorResponse(w http.ResponseWriter, message string, statusCode int) {
|
||||
response := Response{
|
||||
Status: "error",
|
||||
Error: message,
|
||||
}
|
||||
sendJSONResponse(w, response, statusCode)
|
||||
}
|
147
golang-learning/10-projects/03-web-server/server/middleware.go
Normal file
147
golang-learning/10-projects/03-web-server/server/middleware.go
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
middleware.go - 中间件
|
||||
实现了各种HTTP中间件功能
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LoggingMiddleware 日志记录中间件
|
||||
func LoggingMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
|
||||
// 创建响应记录器来捕获状态码
|
||||
recorder := &responseRecorder{
|
||||
ResponseWriter: w,
|
||||
statusCode: http.StatusOK,
|
||||
}
|
||||
|
||||
// 调用下一个处理器
|
||||
next.ServeHTTP(recorder, r)
|
||||
|
||||
// 记录请求日志
|
||||
duration := time.Since(start)
|
||||
log.Printf("[%s] %s %s %d %v",
|
||||
r.Method,
|
||||
r.RequestURI,
|
||||
r.RemoteAddr,
|
||||
recorder.statusCode,
|
||||
duration,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// responseRecorder 响应记录器
|
||||
type responseRecorder struct {
|
||||
http.ResponseWriter
|
||||
statusCode int
|
||||
}
|
||||
|
||||
// WriteHeader 记录状态码
|
||||
func (rr *responseRecorder) WriteHeader(code int) {
|
||||
rr.statusCode = code
|
||||
rr.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
// CORSMiddleware CORS中间件
|
||||
func CORSMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// 设置CORS头
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||
|
||||
// 处理预检请求
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
// 调用下一个处理器
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// RecoveryMiddleware 恢复中间件(处理panic)
|
||||
func RecoveryMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
// 记录panic信息
|
||||
log.Printf("❌ Panic recovered: %v\n%s", err, debug.Stack())
|
||||
|
||||
// 返回500错误
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
|
||||
// 调用下一个处理器
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// AuthMiddleware 认证中间件(示例)
|
||||
func AuthMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// 检查Authorization头
|
||||
token := r.Header.Get("Authorization")
|
||||
if token == "" {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// 这里可以添加实际的token验证逻辑
|
||||
// 为了演示,我们简单检查token是否为"Bearer valid-token"
|
||||
if token != "Bearer valid-token" {
|
||||
http.Error(w, "Invalid token", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// 调用下一个处理器
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// RateLimitMiddleware 限流中间件(简化版)
|
||||
func RateLimitMiddleware(next http.Handler) http.Handler {
|
||||
// 这里可以实现基于IP的限流逻辑
|
||||
// 为了简化,我们只是一个示例框架
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// 实际实现中,这里会检查请求频率
|
||||
// 如果超过限制,返回429状态码
|
||||
|
||||
// 调用下一个处理器
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// ContentTypeMiddleware 内容类型中间件
|
||||
func ContentTypeMiddleware(contentType string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// SecurityMiddleware 安全头中间件
|
||||
func SecurityMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// 设置安全相关的HTTP头
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("X-Frame-Options", "DENY")
|
||||
w.Header().Set("X-XSS-Protection", "1; mode=block")
|
||||
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
|
||||
|
||||
// 调用下一个处理器
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
59
golang-learning/10-projects/03-web-server/server/router.go
Normal file
59
golang-learning/10-projects/03-web-server/server/router.go
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
router.go - 路由管理
|
||||
实现了HTTP路由和中间件管理功能
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// Router 路由器结构体
|
||||
type Router struct {
|
||||
*mux.Router
|
||||
}
|
||||
|
||||
// NewRouter 创建新的路由器
|
||||
func NewRouter() *Router {
|
||||
return &Router{
|
||||
Router: mux.NewRouter(),
|
||||
}
|
||||
}
|
||||
|
||||
// Use 添加中间件
|
||||
func (r *Router) Use(middleware func(http.Handler) http.Handler) {
|
||||
r.Router.Use(middleware)
|
||||
}
|
||||
|
||||
// Methods 设置HTTP方法(链式调用)
|
||||
func (r *Router) Methods(methods ...string) *mux.Route {
|
||||
return r.Router.Methods(methods...)
|
||||
}
|
||||
|
||||
// PathPrefix 路径前缀
|
||||
func (r *Router) PathPrefix(tpl string) *mux.Router {
|
||||
return r.Router.PathPrefix(tpl)
|
||||
}
|
||||
|
||||
// Subrouter 创建子路由
|
||||
func (r *Router) Subrouter() *mux.Router {
|
||||
return r.Router.NewRoute().Subrouter()
|
||||
}
|
||||
|
||||
// HandleFunc 处理函数路由
|
||||
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter, *http.Request)) *mux.Route {
|
||||
return r.Router.HandleFunc(path, f)
|
||||
}
|
||||
|
||||
// Handle 处理器路由
|
||||
func (r *Router) Handle(path string, handler http.Handler) *mux.Route {
|
||||
return r.Router.Handle(path, handler)
|
||||
}
|
||||
|
||||
// ServeHTTP 实现http.Handler接口
|
||||
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
r.Router.ServeHTTP(w, req)
|
||||
}
|
94
golang-learning/10-projects/03-web-server/server/server.go
Normal file
94
golang-learning/10-projects/03-web-server/server/server.go
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
server.go - HTTP服务器核心
|
||||
实现了HTTP服务器的基本功能和生命周期管理
|
||||
*/
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Server HTTP服务器结构体
|
||||
type Server struct {
|
||||
httpServer *http.Server
|
||||
router *Router
|
||||
addr string
|
||||
}
|
||||
|
||||
// NewServer 创建新的服务器实例
|
||||
func NewServer(addr string) *Server {
|
||||
router := NewRouter()
|
||||
|
||||
return &Server{
|
||||
httpServer: &http.Server{
|
||||
Addr: addr,
|
||||
Handler: router,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
},
|
||||
router: router,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
// SetupRoutes 设置路由
|
||||
func (s *Server) SetupRoutes() {
|
||||
// 添加中间件
|
||||
s.router.Use(LoggingMiddleware)
|
||||
s.router.Use(CORSMiddleware)
|
||||
s.router.Use(RecoveryMiddleware)
|
||||
|
||||
// 静态文件服务
|
||||
s.router.HandleFunc("/", HomeHandler).Methods("GET")
|
||||
s.router.PathPrefix("/static/").Handler(
|
||||
http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))),
|
||||
)
|
||||
|
||||
// 健康检查
|
||||
s.router.HandleFunc("/health", HealthHandler).Methods("GET")
|
||||
|
||||
// API路由
|
||||
apiRouter := s.router.PathPrefix("/api").Subrouter()
|
||||
|
||||
// 用户管理API
|
||||
apiRouter.HandleFunc("/users", GetUsersHandler).Methods("GET")
|
||||
apiRouter.HandleFunc("/users", CreateUserHandler).Methods("POST")
|
||||
apiRouter.HandleFunc("/users/{id:[0-9]+}", GetUserHandler).Methods("GET")
|
||||
apiRouter.HandleFunc("/users/{id:[0-9]+}", UpdateUserHandler).Methods("PUT")
|
||||
apiRouter.HandleFunc("/users/{id:[0-9]+}", DeleteUserHandler).Methods("DELETE")
|
||||
|
||||
// 服务器统计
|
||||
apiRouter.HandleFunc("/stats", StatsHandler).Methods("GET")
|
||||
|
||||
// API文档
|
||||
apiRouter.HandleFunc("", APIDocHandler).Methods("GET")
|
||||
}
|
||||
|
||||
// Start 启动服务器
|
||||
func (s *Server) Start() error {
|
||||
fmt.Printf("✅ 服务器启动成功,监听地址: %s\n", s.addr)
|
||||
return s.httpServer.ListenAndServe()
|
||||
}
|
||||
|
||||
// Shutdown 优雅关闭服务器
|
||||
func (s *Server) Shutdown() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
return s.httpServer.Shutdown(ctx)
|
||||
}
|
||||
|
||||
// GetRouter 获取路由器
|
||||
func (s *Server) GetRouter() *Router {
|
||||
return s.router
|
||||
}
|
||||
|
||||
// GetHTTPServer 获取HTTP服务器
|
||||
func (s *Server) GetHTTPServer() *http.Server {
|
||||
return s.httpServer
|
||||
}
|
Reference in New Issue
Block a user