在本篇文章中,将会介绍如何利用go语言去搭建一个高效稳定的rest服务,以及如何去部署它。我们已经搭建好了轮子,好消息是,这一切都是开源的,你可以直接fork我们的项目
ruilisi/go-pangugithub.com,从而节省额外开发的时间。系好安全带,我们要出发了。
(这篇教程可能并非最新的,在github项目里我们会实时更新这篇教程)
效率为王
Go有两个特性让我们去选择用它去开发后端的rest服务。一是Go在并发方面的高性能,在rest服务中,绝大多数的接口都会有很大的负荷,它们在每秒内都要承受成千上万的请求量,因而高并发性能成为一个非常重要的因素。二是Go语言是强类型语言,虽然在编写的过程中会稍微麻烦,但是它不会埋藏一些隐式的bug,从而能保证程序的鲁棒性。同时,完善的包管理,类C的写法都使得任何程序员都能迅速切换技术栈,而不会有太大的负担。
简要介绍
本服务在开发中使用了如下的包/工具,不用感到无从下手,接下的内容我将会一步步开始解释这些是如何发挥他们的作用。
名字 | 描述 |
---|---|
Go | 最近几年最为流行的新兴语言,简单的同时拥有极高的并发性能。 |
Gin | 基于Go语言的web框架,方便灵活的中间件,强大的数据绑定,以及极高的性能 |
Gorm | Go语言的全功能ORM库,用于操作数据库 |
Ginkgo | Ginkgo是一个BDD风格的Go测试框架,旨在帮助你有效地编写富有表现力的全方位测试。 |
JWT | SON Web Tokens,是目前最流行的跨域认证解决方案。 |
Postgres | 高性能开源数据库,当整体负载达到很高时依旧能有强大的性能 |
Redis | 内存数据库,拥有极高的性能 |
Docker | 开发、部署、运行应用的虚拟化平台 |
前期准备
工欲善其事必先利其器,在正式开始开发前,我们需要一件趁手的开发工具,这里我推荐在mac或者linux的环境中在终端下去开发。我们需要使用两个工具,一个是tmux,另一个就是spacevim。
tmux是一个窗口多开的工具,它能够在开许多的窗口,同时还能在窗口里轻松的分屏,能够极大的提升开发的效率。
下图就是我在窗口1里分了3个小屏,主要进行开发,窗口2则是我看的一些其他的一些包或者工具。窗口3则是一些其他服务,以及数据库查询所在。
spacevim是一个集成的VIM IDE它能够轻松的管理插件以及相关的配置,它为不同的语言提供了不同的开发模块,这些模块支持了代码自动补全, 语法检查、格式化、调试、REPL 等特性。
https://github.com/SpaceVim/SpaceVimgithub.com这里有我们整理的相关快捷键的文档,它可能会跟你使用的有所不同,但这些都是我们在日常开发中觉得非常舒适的配置,你可以在配置文件中修改快捷键。
Tmux&Vim常用快捷指令 · 语雀www.yuque.com如果你还不会使用这两个工具,那么可以去看一下的教程或是文档。
Tmux 使用教程 - 阮一峰的网络日志www.ruanyifeng.com我们还需要进行一个准备,就是有一些开发的网站可能会被block或是速度比较慢,这个时候我们可能就需要额外的一些方法去解决这个问题,你可以在vagrant虚拟机里完成上述配置以及解决这个问题,碍于篇幅,这里我们就不去赘述这个问题了。
准备好数据库
我们这里需要使用两个数据库,一个是postgresql数据库,一个就是redis数据库。为什么会需要这两个数据库呢?因为我们的rest api服务有两种数据类型,一种是长效的,也就是需要一直保存的数据,像是用户的信息。还有一种就是短期的热数据,像是token,短信code,这些数据很快就会过期,因而我们把它们储存在内存数据库redis中,能极大提升效率,也不会让这些数据去污染postgresql数据库,加大其的负担。
如何使用它们的方法这里也不在赘述,如果你有学习过sql,那么这两个数据库你都能很快上手。我这写了一个常用命令文档
postgresql 和 redis · 语雀www.yuque.com开启服务
接下来我们拉取项目,我们首先来观察一下整个项目的结构是什么样的。
文件 | 功能 |
---|---|
application.yml | 配置文件,包含基本信息 |
args | 包含获取url的params的函数 |
conf | 获取配置文件的函数 |
controller | router使用的handler控件,包含各种操作具体内容 |
db | db操作,像是打开数据库 |
jwt | jwt相关内容 包含生成jwt与验证jwt的函数 |
main.go | 程序主函数,执行时增加-db参数可选择不同的内容,create创建数据库,migrate更新表结构,drop删除数据库 |
middleware | 中间件,验证token是否正确 |
models | 基础的结构以及一些基本的数据库操作 |
params | 数据绑定的结构 |
redis | 包含连接redis和redis操作函数 |
router | 路由 |
test | 测试 |
我们直接开干,首先就是来看根目录下的配置文件application.yml
DEVISE_JWT_SECRET_KEY: RANDOM_SECRET
HTTP_PORT: 3002
BASE_DATABASE_URL: postgres://postgres:postgres@localhost:5432
DATABASE_URL: postgres://postgres:postgres@localhost:5432/go_pangu_development?sslmode=disable
DATABASE_TESTURL: postgres://postgres:postgres@localhost:5432/go_pangu_test?sslmode=disable
REDIS_URL: redis://localhost:6379/7
WORKERS: CollectIpWorker,QcloudSmsWorker
SMS_APPID:
SMS_APPKEY:
SMS_TEMPID:
SMS_APPLYTEMPID:
这里的你需要更改的就是 postgres:// 后跟的账号和密码,其他的都可以不去修改。
接着运行主程序
go
如果一切顺利,就会如下图所示
我们尝试请求一下这个服务,就是用最简单的ping,你可以在浏览器,也可以使用postman(建议)。如果成功返回pong,那么我们的服务就一切正常。与此同时,服务器也会留下请求记录。
路由
路由被统一写在了router文件夹下
func
后面起的几个路由,当使用middleware.Auth的时候,则是使用了jwt token来验证身份。这些token在登录时会生成,而生成token的过程中用到了数据库的操作,所以我们先来看数据库操作。
数据库操作
postgresql
postgresql 的相关内容在db,models这两个文件中。
db 文件夹负责连接数据库后声明一个DB变量让其他package中函数操作中使用。
main函数的create migrate功能所使用的函数也在这里。
var
models 文件夹定义了数据库的表结构,以及一些常用的数据库操作,像是查询,删除一些数据。我们使用的是gorm包。
GORM 指南gorm.iopackage
redis
redis 的相关内容主要在redis文件夹中,其中主要包括了连接redis数据库以及进行redis数据库操作的函数。
var
token
有些接口,只能在用户进行登录之后才能进行调用,怎么来判断用户是否登录了呢。我们这里使用的是jwt,json web token。生成token,验证token以及注销token的函数都放在了jwt文件夹中了。这些操作生成token都被存储在了redis数据库中。
如果你不熟悉jwt,可以看这篇文档。
JSON Web Token 入门教程www.ruanyifeng.comtype
在登录的过程中,我们生成token
payload
最后我们写一个中间件,来进行判断中间件是否合法,其中sub是用户的uuid,scp是用户类型。
func
handler控件
这个部分就是路由实际使用的控件了,也就是写入接口请求后的逻辑的所在。它们被放在controller文件夹下。主要负责就是处理请求的参数后进行各种操作,像是数据库操作来获取数据进行返回。在路由部分我们已经进行了token处理,所以在handler里我们可以直接获取用户类型和他的uuid。
这里还用到了params文件夹,这里面保存了进行数据绑定的结构体。当然也可以使用map[string]interface{}类型的变量来绑定一切数据,但是需要类型断言,有时候比较繁琐,如何取舍,看实际情况而定。
func
读取配置文件
为了获取配置文件的内容,conf文件夹下有如下的函数
func
当需要使用时,只要像这样调用就行
url
测试
测试在test文件夹下,这里我们使用的是ginkgo来进行测试,Ginkgo是一个BDD风格的Go测试框架,旨在帮助你有效地编写富有表现力的全方位测试。进入测试文件夹,使用ginkgo就可以测试,不用担心可能会打乱数据库内容,之前我们在运行 go run main.go 时就额外生成了一个测试数据库,不会影响在正常开发数据里的内容。
如果你不了解ginkgo可以看这篇
Ginkgo学习笔记blog.gmem.cc运行结果如下
部署
使用make release或者debug 后 会生成可执行的server,接着就可以使用docker部署在服务器上。<br>
相关文件在根目录下的Makefile Dockerfile
FROM