Go application architecture with net/http 1.22+ routing, project structure patterns, graceful shutdown, and dependency injection. Use when building Go web servers, designing project layout, or structuring application dependencies.
| 主题 | 参考 |
|---|---|
| 扁平与模块化项目布局、迁移信号 | references/project-structure.md |
| 带信号处理的优雅关闭 |
Go 1.22 升级了 http.ServeMux,支持基于方法的路由和路径参数,消除了使用第三方路由器的最常见原因。
go
mux := http.NewServeMux()
mux.HandleFunc(GET /api/users, s.handleListUsers)
mux.HandleFunc(GET /api/users/{id}, s.handleGetUser)
mux.HandleFunc(POST /api/users, s.handleCreateUser)
mux.HandleFunc(DELETE /api/users/{id}, s.handleDeleteUser)
go
func (s Server) handleGetUser(w http.ResponseWriter, r http.Request) {
id := r.PathValue(id)
if id == {
http.Error(w, 缺少id, http.StatusBadRequest)
return
}
user, err := s.users.GetUser(r.Context(), id)
if err != nil {
s.logger.Error(获取用户, err, err, id, id)
http.Error(w, 内部错误, http.StatusInternalServerError)
return
}
w.Header().Set(Content-Type, application/json)
json.NewEncoder(w).Encode(user)
}
go
// 尾随斜杠的精确匹配 -- 仅服务于 /api/files/
mux.HandleFunc(GET /api/files/, s.handleListFiles)
// 通配符匹配到路径末尾 -- /api/files/path/to/doc.txt
mux.HandleFunc(GET /api/files/{path...}, s.handleGetFile)
新的 ServeMux 使用最具体优先的规则:
Server 结构体是应用程序的中央依赖容器。它持有所有共享依赖并实现 http.Handler。
go
type Server struct {
db *sql.DB
logger *slog.Logger
router *http.ServeMux
}
func NewServer(db sql.DB, logger slog.Logger) *Server {
s := &Server{
db: db,
logger: logger,
router: http.NewServeMux(),
}
s.routes()
return s
}
func (s *Server) routes() {
s.router.HandleFunc(GET /api/users/{id}, s.handleGetUser)
s.router.HandleFunc(POST /api/users, s.handleCreateUser)
s.router.HandleFunc(GET /healthz, s.handleHealth)
}
func (s Server) ServeHTTP(w http.ResponseWriter, r http.Request) {
s.router.ServeHTTP(w, r)
}
在 http.Server 级别或按路由应用中间件:
go
// 包装整个服务器
httpServer := &http.Server{
Addr: :8080,
Handler: requestLogger(s),
}
// 或按路由
s.router.Handle(GET /api/admin/, adminOnly(http.HandlerFunc(s.handleAdmin)))
go
func requestLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
slog.Info(请求, method, r.Method, path, r.URL.Path, dur, time.Since(start))
})
}
根据项目规模选择:
从扁平结构开始。当看到参考文档中描述的迹象时进行迁移。
每个生产级Go服务器都需要优雅关闭。该模式使用 signal.NotifyContext 监听操作系统信号,使用 http.Server.Shutdown 排空连接。
go
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
defer cancel()
// ... 在goroutine中启动服务器 ...
<-ctx.Done()
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second)
defer shutdownCancel()
httpServer.Shutdown(shutdownCtx)
完整的清理顺序模式见 references/graceful-shutdown.md。
加载 project-structure.md 时:
加载 graceful-shutdown.md 时:
加载 dependency-injection.md 时:
go
// 错误 -- 不可测试,隐藏依赖
var db *sql.DB
func handleGetUser(w http.ResponseWriter, r *http.Request) {
db.QueryRow(...)
}
通过Server或Service结构体传递 db。
不要以 gin.Default() 或 echo.New() 开始。以 http.NewServeMux() 开始。只有在遇到标准库的真正限制时才引入框架。
一个包含50个文件的 handlers 包不是组织。按领域分组(user、order、billing),而不是按技术层。
go
// 错误 -- 不可见的副作用,不可测试
func init() {
db, = sql.Open(postgres, os.Getenv(DATABASEURL))
}
所有初始化属于 main() 或 run() 函数,以便可以测试并处理错误。
go
// 错误 -- 将处理器耦合到环境
func (s Server) handleSendEmail(w http.ResponseWriter, r http.Request) {
apiKey := os.Getenv(SENDGRIDAPIKEY) // 不要这样做
}
通过构造函数注入配置值或客户端。
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 go-architect-1776097450 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 go-architect-1776097450 技能
skillhub install go-architect-1776097450
文件大小: 14.15 KB | 发布时间: 2026-4-14 14:26