Golang Web应用架构设计与实践
Golang Web应用架构设计与实践 我刚开始使用Go语言。我想用标准库编写一个Web应用程序。请问推荐的Web应用程序文件结构是什么样的?
感谢。我几天没来这里了,刚刚看到这个。正准备阅读这篇文章。
更多关于Golang Web应用架构设计与实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你们认为标准库适合用来开发Web应用程序吗?还是我应该使用其他工具?
请查看这篇文章:《编写Web应用程序》
CryptoBaymax:
你们认为标准库适合用来开发Web应用程序吗?
是的。
你的cmd目录是什么?这将是我用Go编写的第一个Web应用程序。我一直都是用PHP来编写这类应用的。
我发现这篇Medium文章中的建议非常实用且直观。
使用标准库入门相当容易,但我确实发现使用第三方库能为应用程序代码提供某种结构。
就个人而言,我使用Mux并发现自己能够更快地启动项目。
这对我来说很有道理,看起来是个不错的结构。不过有几点我不太确定。handler目录是做什么用的?模板和CSS文件应该放在哪里?main.go文件里应该包含哪些内容?是只包含主要的逻辑和路由,还是也应该包含服务器配置信息?
Go语言通常避免在常规应用中使用多个包/文件夹。 一个不错的入门示例:
/cmd
.. main.go
/myapp
.. model.go
.. server.go <-- 你的http处理程序放在这里
.. service.go
/internals
.. someobscurestuff.go
这对我来说有点新鲜。我一直都是用PHP从零开始写项目。不喜欢用框架,所以总是自己从头开始写。但后来发现有些事情本可以做得更好,比如使用模板之类的东西,而不是写那么多不必要的代码。还有模型,我从未使用过。在阅读相关资料后,我发现它们非常有用。所以我打算在下一个项目中使用这些东西。
可能是最简洁的架构
├── driver // 所有数据库连接(mysql、psql、mongo)
├── handler // 所有处理器
│ └── http
│ └── websocket
|── models // 所有全局数据模型(请求json模型、响应模型等)
└── repository // 数据库查询接口
└── user // 查询用户的数据库函数
└── posts // 查询帖子...
看看这个,
我曾经将我的 main.go 文件放在项目的根目录中,这样当有人运行 “go get” 时,我的应用程序就会自动安装。然而,将 main.go 文件和我的应用程序逻辑放在同一个包中有两个后果:
- 这使得我的应用程序无法作为库使用。
- 我只能有一个应用程序二进制文件。
我找到的解决这个问题的最佳方法是简单地在我的项目中使用一个 “cmd” 目录,其中的每个子目录都是一个应用程序二进制文件。我最初在 Brad Fitzpatrick 的 Camlistore 项目中发现了这种方法,他使用了多个应用程序二进制文件:
对于使用Go标准库构建Web应用,推荐采用以下文件结构,这种结构清晰且易于维护:
myapp/
├── cmd/
│ └── web/
│ └── main.go # 应用入口点
├── internal/
│ ├── handlers/ # HTTP处理器
│ │ ├── user.go
│ │ └── home.go
│ ├── models/ # 数据模型
│ │ └── user.go
│ ├── middleware/ # 中间件
│ │ └── auth.go
│ └── config/ # 配置
│ └── config.go
├── pkg/
│ └── utils/ # 可复用工具
│ └── validation.go
├── static/ # 静态文件
│ ├── css/
│ ├── js/
│ └── images/
├── templates/ # HTML模板
│ ├── base.html
│ ├── home.html
│ └── user.html
├── go.mod
└── go.sum
具体实现示例:
cmd/web/main.go - 应用入口:
package main
import (
"log"
"net/http"
"myapp/internal/handlers"
"myapp/internal/middleware"
)
func main() {
mux := http.NewServeMux()
// 静态文件服务
fs := http.FileServer(http.Dir("./static"))
mux.Handle("/static/", http.StripPrefix("/static/", fs))
// 路由设置
mux.HandleFunc("/", handlers.HomeHandler)
mux.HandleFunc("/users", handlers.UserHandler)
// 应用中间件
handler := middleware.Logging(mux)
handler = middleware.Auth(handler)
log.Println("服务器启动在 :8080")
log.Fatal(http.ListenAndServe(":8080", handler))
}
internal/handlers/home.go - 处理器示例:
package handlers
import (
"html/template"
"net/http"
)
func HomeHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
tmpl := template.Must(template.ParseFiles(
"templates/base.html",
"templates/home.html",
))
data := struct {
Title string
}{
Title: "首页",
}
tmpl.ExecuteTemplate(w, "base", data)
}
internal/middleware/auth.go - 中间件示例:
package middleware
import (
"net/http"
)
func Auth(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 简单的认证逻辑
token := r.Header.Get("Authorization")
if token == "" {
http.Error(w, "未授权", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
internal/middleware/logging.go - 日志中间件:
package middleware
import (
"log"
"net/http"
"time"
)
func Logging(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))
})
}
这种结构遵循Go项目的标准布局,将不同职责的代码分离到相应目录中,便于团队协作和代码维护。


