之前在研究区块链,然后看到很多区块链项目都是基于开发的,包括以太坊官方的go-。了解了Go是一个产品后,很多人都说它拥有C/C++的性能,同时也拥有脚本语言的开发效率。我被吸引了并开始了解它。方便后端遇到性能瓶颈以及区块链的发展。
再加上最近小程序的流行,这个技术栈也需要学习和理解。我只是想做一个简单的抽奖小程序。后端可以用Go实现,可以学习小程序开发。一石二鸟,起之。动手实践永远是最好的学习方式。
1.整体背景结构
后端架构
整体后端结构设计如上图:
这样的设计,在彩票这样的场景下,已经可以保证足够的并发和流量了。如果想要增加并发量,可以配置负载均衡进行动态伸缩,然后增加云数据库的处理能力。有时间我会写一下如何进行性能评估以及相应的升级来提高并发。
2、抽奖流程设计
因为我每天工作很忙,没有太多时间。只要准备先研究最简单的彩票逻辑,如果有时间和精力,然后再迭代。用户可以进入小程序创建抽奖活动并设置活动主题、抽奖时间、奖品和数量。然后就可以分享了,其他用户可以点击参与抽奖。到达抽奖时间后,将进行随机抽奖,每位参与抽奖的用户最多只能中奖一次。抽奖结束后,将向所有抽奖用户发送消息提醒。
其实可以简单的用抽签来进行粗略的划分:
一些重要的接口
3.API文档设计
接口文档非常重要,值得认真编写。我认为这是后端开发的基本素质。无论项目大小,良好的文档都是必须的。文档一旦编写完毕,就会带来很多好处。随着时间的推移和迭代,我们仍然可以很好地理解每个接口。接口文档可以将后端开发与外部依赖分离,实现前后端解耦。同时,编写接口文档的过程实际上也是一个思考和梳理的过程。通过详细的讨论和思考,可以明确一些细节,避免一些陷阱。
以下是我维护的文档,从基本描述、域名、基本路径等开始。
然后是每个接口的详细描述,定义了请求和返回结构,以及每个参数的含义和格式。
有关接口的信息
我一般都会在git上维护最新的md格式的接口文档。如果有协作,如果其他人对接口有疑问,不需要每次在沟通中争论,按照文档中的说明调用即可。
4. 实现 4.1 web框架选择
研究了Go的Web框架,最常用的是echo和gin,所以就选一个吧。我选择了echo,感觉文档更完整一点。但与其他语言的Web框架相比,echo的文档太少且不完整,学习和使用的成本较高。
在使用echo的时候,我先把官方文档整体看了一下。最好最全的资料就是官方文档的介绍,所以我要一直坚持学习英语。附网址:
这里的主要流程基本是一样的,注册url处理函数,然后增删改查操作,以及各种内部逻辑。每个请求都带有内部自定义,并在 echo 中进行验证。
4.2 数据库操作 4.2.1
我用的是Go--这个包,地址:
至于如何使用crud,我翻阅了使用文档,地址为:
代码语言:
复制
import "database/sql" import _ "github.com/go-sql-driver/mysql" db, err = sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/lottery?charset=utf8")
使用()来绑定参数和查询。这里比较麻烦的是获取db中的一行数据,需要Scan()逐一赋值。取出的数据很多的时候有点麻烦,但是我还是喜欢自己控制SQL语句。有些ORM框架使用起来非常简单,但是在编程思维和编写SQL方面没有足够的训练。当你自己写sql时,你会考虑如何优化它。我经常会问自己更多的问题:我可以少执行一次SQL查询吗?查询sql语句能否更加高效?设计的SQL表能不能更好一点?
代码语言:
复制
var ( id int name string ) rows, err := db.Query("select id, name from users where id = ?", 1) if err != nil { log.Fatal(err) } defer rows.Close() for rows.Next() { err := rows.Scan(&id, &name) if err != nil { log.Fatal(err) } log.Println(id, name) } err = rows.Err() if err != nil { log.Fatal(err) }
代码语言:
复制
_, err = db.Exec("update events set status = ?,cancel_time=? where id = ? and status=?", util.DBEventStatusCANCELED, time.Now().Unix(), queryEvent.ID, util.DBEventStatusINIT)
以上是我用来将抽奖从初始状态设置为取消状态的SQL语句,并使用db.Exec执行更新、删除等语句。
对于交易,可以查看文档了解详情:
代码语言:
复制
tx, err := db.Begin() if err != nil { log.Fatal(err) } defer tx.Rollback() stmt, err := tx.Prepare("INSERT INTO foo VALUES (?)") if err != nil { log.Fatal(err) } defer stmt.Close() for i := 0; i < 10; i++ { _, err = stmt.Exec(i) if err != nil { log.Fatal(err) } } err = tx.Commit() if err != nil { log.Fatal(err) }
4.2.2
每个请求都需要身份验证,这里使用的是身份验证。该库用于操作。
大家的流程都是类似的:连接,然后执行put和get操作。这里有一个简单的封装示例,大家可以学习一下。
4.3 微信登录流程
这里我们可以讲一下微信用户使用小程序的登录流程。
一个。用户进入小程序。小程序使用wx.()登录微信后台。如果登录成功,将获得一个代码。实际返回是这样的:
代码语言:
复制
{errMsg: "login:ok", code: "001nnSQv1QStGa0X1bSv13u7Rv1nnSQA”}
b.小程序将此代码发送到我们自己的后端。
c.后端收到此代码后,拼接一个URL到微信后端,获取微信用户的信息。
代码语言:
复制
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
各字段含义:
:此处填写小程序
:小程序
:小程序发送的代码
:授权类型,这里填写即可
我抓起一条日志,查看微信返回的数据。其中,用户对应的会话密钥;、证书的有效时间,单位:秒;、用户的唯一标识。
代码语言:
复制
{"time":"2018-10-13T18:19:41.472758451+08:00","level":"DEBUG","prefix":"echo","file":"auth.go","line":"52","message":"result:map[session_key:ig6tsRoILO2cpxCnk0TXVg== expires_in:7200 openid:(隐私删除)]”}
d.在自己的后台定义登录状态,返回给小程序,即可自定义登录状态。这个时候用户就相当于登录成功了,所以我们给这个用户一个自定义的,然后每次请求都需要携带这个进行验证。
4.4 抽奖活动状态机设计
事实上,整个后端业务逻辑重点是根据彩票的状态进行变化。因此,对于每次启动的彩票,我定义了几个状态。状态机如下:
代码语言:
复制
//数据库中抽奖活动的状态常量, const ( DBEventStatusINIT = 0 //抽奖中,活动创建后此状态,允许参加抽奖 DBEventStatusOPENING = 1 //开奖中,不允许抽奖了 DBEventStatusOPEND = 2 //已经开奖了, DBEventStatusCANCELED = 9 //活动取消 )
抽奖的状态机
5. 总结
完成这件事是相当困难的。我必须学习很多东西并阅读很多文档。比如需要阅读小程序的官方文档,否则后端无法配合登录等。我使用的语言是Go,不是很熟悉。我会一边做一边学习,阅读echo框架的文档。然后设计抽奖的整个流程,设计数据库,设计接口请求和返回格式,编写接口文档。由于大块时间不多,中断后重新连接效率低下。不过,做完整个过程,我感觉自己对Go和小程序有了比较全面的了解。接下来我会继续努力。
那么如何利用它来快速部署呢?如何创建完整的自动化编译、部署、测试流程?以后有时间我会继续总结并发表这些。