golang web 方案
概要轻量的基于 golang 的 web 开发实践. golang 上手简单,第三方库丰富,对于业务没那么复杂的项目,作为 API 的后端也是不错的选择. 下面是对 golang 作为 API 后端的 web 开发实践总结. 开发API 后端的功能模块基本已经固定,基于自己的项目,主要使用了以下模块:
web 框架golang 的 API 框架有很多,我在项目中选择了 gin 框架. 当时是出于以下几点考虑:
虽然选择了 gin,但是本文中使用的各个模块都不是强依赖 gin 的,替换任何一个模块的代价都不会太大. gin 的使用很简单,主要代码如下: r := gin.Default() if gin.Mode() == "debug" { r.Use(cors.Default()) // 在 debug 模式下,允许跨域访问 } // ... 设置路由的代码 if err := r.Run(":" + strconv.Itoa(port)); err != nil { log.Fatal(err) } 数据库数据库这层,选用了 beego ORM 框架,它的文档比较好,对主流的几种关系数据库也都支持. 表结构的定义: type User struct { Id string `orm:"pk" json:"id"` UserName string `orm:"unique" json:"username"` Password string `json:"password"` CreateAt time.Time `orm:"auto_now_add"` UpdateAt time.Time `orm:"auto_now"` } func init() { orm.RegisterModel(new(User)) } 数据库的初始化: // mysql 配置,postgresql 或者 sqlite 使用其他驱动 orm.RegisterDriver("default",orm.DRMySQL) // 注册驱动 var conStr = fmt.Sprintf("%s:%[email?protected](%s:%d)/%s?charset=utf8&loc=Local",c.DB.UserName,c.DB.Password,c.DB.Host,c.DB.Port,c.DB.DBName) orm.RegisterDataBase("default","mysql",conStr) // sync database orm.RunSyncdb("default",false,false) 认证认证采用 jwt token,使用了 gin-jwt 中间件. 加了认证中间件之后,可以配置路由是否需要认证: authMiddleware := controller.JwtMiddleware() // *不需要* 认证的路由 r.POST("/register",controller.Register) r.POST("/login",authMiddleware.LoginHandler) // *需要* 认证的路由 authRoute := r.Group("/auth") authRoute.Use(authMiddleware.MiddlewareFunc()) { authRoute.GET("/test",func(c *gin.Context) { fmt.Println("hello") }) } 日志项目不是很复杂,日志采用了文件的方式,选择了 beego logs 模块. 虽然使用了 beego logs,但是为了方便以后替换 logs 模块,在 beego logs 又封装了一层. // Logger type Logger interface { Debug(format string,v ...interface{}) Info(format string,v ...interface{}) Warn(format string,v ...interface{}) Error(format string,v ...interface{}) } // 支持 console 和 file 2 种类型的 log func InitLogger(level,logType,logFilePath string) error { consoleLogger = nil fileLogger = nil if logType == ConsoleLog { consoleLogger = NewConsoleLogger(level) // 这里实际是通过 beego logs 来实现功能的 } else if logType == FileLog { fileLogger = NewFileLogger(logFilePath,level) // 这里实际是通过 beego logs 来实现功能的 } else { return fmt.Errorf("Log type is not validn") } return nil } 配置配置采用 toml 格式,配置文件中一般存放不怎么改变的内容,改动比较频繁的配置还是放在数据库比较好. import ( "github.com/BurntSushi/toml" ) type Config struct { Server serverConfig `toml:"server"` DB dbConfig `toml:"db"` Logger loggerConfig `toml:"logger"` File fileConfig `toml:"file"` } type serverConfig struct { Port int `toml:"port"` } type dbConfig struct { Port int `toml:"port"` Host string `toml:"host"` DBName string `toml:"db_name"` UserName string `toml:"user_name"` Password string `toml:"password"` } type loggerConfig struct { Level string `toml:"level"` Type string `toml:"type"` LogPath string `toml:"logPath"` } type fileConfig struct { UploadDir string `toml:"uploadDir"` DownloadDir string `toml:"downloadDir"` } var conf *Config func GetConfig() *Config { return conf } func InitConfig(confPath string) error { _,err := toml.DecodeFile(confPath,&conf) return err } 静态文件服务本工程中静态文件服务的目的是为了发布前端. 前端采用 react 开发,build 之后的代码放在静态服务目录中. 使用 gin 框架的静态服务中间件,很容易实现此功能: // static files r.Use(static.Serve("/",static.LocalFile("./public",true))) // 没有路由匹配时,回到首页 r.NoRoute(func(c *gin.Context) { c.File("./public/index.html") }) 上传/下载上传/下载 在 gin 框架中都有支持.
发布基于上面几个模块,一般业务不是很复杂的小应用都可以胜任. 开发之后,就是打包发布. 因为这个方案是针对小应用的,所以把前后端都打包到一起作为一个整体发布. docker 打包之所有采用 docker 方式打包,是因为这种方式易于分发. docker file 如下: # 编译前端 FROM node:10.15-alpine as front-builder WORKDIR /user ARG VERSION=no-version ADD ./frontend/app-ui . RUN yarn RUN yarn build # 编译前端 FROM golang:1.12.5-alpine3.9 as back-builder WORKDIR /go RUN mkdir -p ./src/app-api ADD ./backend/src/app-api ./src/app-api RUN go install app-api # 发布应用 (这里可以用个更小的 linux image) FROM golang:1.12.5-alpine3.9 WORKDIR /app COPY --from=front-builder /user/build ./public COPY --from=back-builder /go/bin/app-api . ADD ./deploy/builder/settings.toml . CMD ["./app-api","-f","./settings.toml","-prod"] 部署中遇到的问题时区问题docker 的官方 image 基本都是 UTC 时区的,所以插入数据库的时间一般会慢 8 个小时. 所以,在 docker 启动或者打包的时候,需要对时区做一些处理.
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |