golang web 方案

  • 概要
  • 开发
    • web 框架
    • 数据库
    • 认证
    • 日志
    • 配置
    • 静态文件服务
    • 上传/下载
  • 发布
    • docker 打包
    • 部署中遇到的问题
      • 时区问题

概要

轻量的基于 golang 的 web 开发实践.

golang 上手简单, 第三方库丰富, 对于业务没那么复杂的项目, 作为 API 的后端也是不错的选择. 下面是对 golang 作为 API 后端的 web 开发实践总结.

开发

API 后端的功能模块基本已经固定, 基于自己的项目, 主要使用了以下模块:

  1. web 框架: 整个方案的核心
  2. 数据库: orm 框架
  3. 认证: 访问的安全
  4. 日志: 辅助调试和运维
  5. 配置: 提高服务的灵活性
  6. 静态文件服务: 部署打包后的前端
  7. 上传/下载: 其实也是 web 框架提供的功能, 单独提出来是因为和一般的 JSON API 不太一样

web 框架

golang 的 API 框架有很多, 我在项目中选择了 gin 框架. 当时是出于以下几点考虑:

  1. 成熟度: gin 早就进入 v1 稳定版, 使用的项目也很多, 成熟度没有问题
  2. 性能: gin 的性能在众多 golang web 框架中不是最好的, 但也不差, 具体可以参见 gin 的 README
  3. 活跃度: github 上的 commit 可以看出, gin 虽然很稳定, 更新频率还可以
  4. 周边支持: gin 的插件非常多, 还有个 contrib 项目, 常用的各种插件基本都有, 另外, 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 valid\n")
  }

  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 框架中都有支持.

  • 上传

    func UploadXls(c *gin.Context) {
      // ... 省略的处理
    
      // upload form field name: uploadXls, 这个名字和前端能对上就行
      // file 就是上传文件的文件流
      file, header, err := c.Request.FormFile("uploadXls")
      if err != nil {
        Fail(c, "param error: "+err.Error(), nil)
        return
      }
    
      // ... 省略的处理
    }
  • 下载
    func DownloadXls(c *gin.Context) {
      // ... 省略的处理
    
      c.File(downloadPath)
    }

发布

基于上面几个模块, 一般业务不是很复杂的小应用都可以胜任. 开发之后, 就是打包发布. 因为这个方案是针对小应用的, 所以把前后端都打包到一起作为一个整体发布.

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 启动或者打包的时候, 需要对时区做一些处理.

  1. 数据库连接的设置

    // 连接字符串中加上: loc=Local
    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)
  2. 数据库镜像的设置 (环境变量中设置时区)
    # -e TZ=Asia/Shanghai 就是设置时区
    docker run --name xxx -e TZ=Asia/Shanghai -d mysql:5.7
  3. 应用镜像的设置 (docker-compose.yml) 在 volumes 中设置时区和主机一样
    services:
    user:
      image: xxx:latest
      restart: always
      networks:
        - nnn
      volumes:
        - "/etc/localtime:/etc/localtime:ro"

原文地址:https://www.cnblogs.com/wang_yb/p/10859900.html

时间: 2024-10-03 08:22:49

golang web 方案的相关文章

net core与golang web

Asp.net core与golang web简单对比测试 最近因为工作需要接触了go语言,又恰好asp.net core发布RC2,就想简单做个对比测试. 下面是测试环境: CPU:E3-1230 v2 内存:16G 电脑有点不给力 操作系统:Centos7.0(虚拟机单核2G内存) asp.net core rc2 golang v1.7beta1 下面是各自的代码: go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

golang web sample

一.学习想法 用两天的时间学习golang,但这次是先不看书的,直接写代码先. 我们常习惯边看书边学习写代码,但发现过程是比较缓慢的,所以我就先想写代码, 边写边查.就我们所知,web app一般是基于MVC框架,那么我可以先写数据层,从先写 数据库查数据开始,可以用DAO模式,但这里我只是用一个简单的sample,没有那么复杂. 接着写完数据层,再写视图层,视图层即为app逻辑层:之后再写http前端渲染层. 一步一步,遇到不懂就查. 二.学习资源 Golang电子书 An Introduct

[Amaze UI] 如何推进 mobile first 的前端 Web 方案

背景:云适配创立之初,我们就开始积累自己的前端框架,同时也借鉴了Bootstrap等国外框架的优点.在内部使用过程中,大家一致反映不错,我们就希望把这个产品开源,希望分享给更多的人,也希望更多的人来贡献代码,来共建中国前端开源生态环境. 由于Amaze UI目前处在内测期,我们希望能尽可能多的收集到优秀的.有建设性的反馈建议和看法,与广大优秀前端开发者共同完善Amaze UI 的功能,推动中国移动跨屏前端技术的发展.(内测地址:http://amazeui.org/landing) 下面提前跟大

Golang Web编程的Get和Post请求发送与解析

本文的是一篇入门文章,通过一个简单的例子介绍Golang的Web编程主要用到的技术. 文章结构包括: Client-Get 请求 Client-Post 请求 Server 处理 Get 和 Post 数据 在数据的封装中,我们部分采用了json,因而本文也涉及到Golang中json的编码和解码. 一.Client-Get package main import ( "fmt" "net/url" "net/http" "io/iou

Zabbix(五):高级应用-web方案、被动监控、基于snmp协议被动监控、proxy配置测试实例

1.web方案 web scenario:web监控方案,web场景: web scenarios指的是监控指定的web站点的资源下载及页面响应时间等数据指标: (1)创建web监控需要先定义一个web scenario(方案): 一个web方案包括一个或多个HTTP请求或步骤(steps) 每次监控都是按照预先定义的步骤的顺序执行: (2)通过web监控方案可以获取到下列信息: 整个web方案中所有步骤的速度和响应时间,以及平均下载速度和平均响应时间: 失败的步骤号 失败的报错信息 (3)在设

【One by one系列】一步步学习Golang web框架Gin

一步步学习Golang web框架Gin 建立项目 go mod 管理依赖 cd $gopath\src\github.com\carfield go mod init 就可以看到在src\github.com\carfield 生成了go.mod文件 module github.com/carfield go 1.13 下载gin包 go get -u github.com/gin-gonic/gin ps:由于众所周知的原因,大概率是下不动,所以请修改代理 修改代理 go env -w GO

golang web framework--Martini

Martini是一个功能强大的软件包,用于在Golang中快速编写模块化Web应用程序/服务. 下载 $ go get github.com/go-martini/martini Demo server.go //server.go package main import "github.com/go-martini/martini" func main() { m := martini.Classic() m.Get("/", func() string { re

Asp.net core与golang web简单对比测试

最近因为工作需要接触了go语言,又恰好asp.net core发布RC2,就想简单做个对比测试. 下面是测试环境: CPU:E3-1230 v2 内存:16G 电脑有点不给力 操作系统:Centos7.0(虚拟机) asp.net core rc2 golang v1.7beta1 下面是各自的代码: go package main import ( "fmt" "net/http" ) func main() { fmt.Println("This is

[读书] Golang Web 编程

1.golang的安装工具 1.1 GVM 第三方开发的Go多版本管理工具 2.golang环境变量 2.1 GOROOT=D:\go (golang 安装目录) 2.2 GOBIN=D:\go\bin (golang 生成的BIN目录) 2.3 GOPAT=D:\code\golang (golang 工作区,允许多个目录,;隔开) 执行goget命令时,会将包放在第一个配置的gopath目录中 GOPATH约定三个子目录:src(源码) .bin(编译生成的文件, .a).pkg(编译后的可