10.23 go
<h2>go web</h2>
<h3>0. gitlab 地址</h3>
<p><a href="http://119.23.216.19:10080/apiservice/go-darkroomliteweb">http://119.23.216.19:10080/apiservice/go-darkroomliteweb</a></p>
<h3>1. 最外层的异常处理 (告警)</h3>
<p>使用 app/middleware/recover.go </p>
<h3>2. 路由注册</h3>
<p>在 app/route.go 中定义即可</p>
<pre><code>func InitRouter(Listen string) error {
router := gin.Default()
//add middleware to deal panic
router.Use(middleware.Recover())
demo := router.Group("/demo")
{
demo.POST("/example1", controller.ExampleOne) // 在这里定义!!!!
}
return router.Run(Listen)
}</code></pre>
<h3>3. request 参数接收</h3>
<p><img src="https://www.showdoc.cc/server/api/common/visitfile/sign/9d5466affcb7f6f5a916bb475d70b8b2?showdoc=.jpg" alt="" /></p>
<h3>4. 参数验证</h3>
<p>参数较少,暂时可以用结构体自己封装办法,也可以引入 "gopkg.in/go-playground/validator.v9" 来验证,待定</p>
<pre><code>
type exampleOneparams struct {
Row int `form:"row" json:"row"`
PageDepend int `form:"page_depend" json:"page_depend"`
TagId int `form:"tag_id" json:"tag_id"`
}
func (ex *exampleOneparams)validate() error{
if ex.Row < 1 || ex.Row > 10{
return errors.New("row error")
}
if ex.PageDepend < -1{
return errors.New("page_depend error")
}
if ex.TagId < 1 {
return errors.New("tag_id error")
}
return nil
}
</code></pre>
<h3>5. 调用 service 层</h3>
<p>引包然后使用办法即可</p>
<pre><code>// 控制器调用 service 层, 获取小程序 + tab 下的 id
idList, err := service.ListAppTabArticleId(appid, params.TagId, params.PageDepend, params.Row)
if err != nil {
commonGin.Fail(1, err.Error())
return
}
// service 层
func ListAppTabArticleId(appId string, tagId int, startId int, row int) ([]interface{}, error) {
redisKey := rediskey.ListKey + appId + ":" + string(tagId)
conn := common.Db.Redis.Get()
defer conn.Close()
reply, err := redis.Values(conn.Do("zRevRangeByScore", redisKey, startId, "-inf", "LIMIT", 0, row))
if err != nil {
return nil, err
}
return reply,nil
}
</code></pre>
<h3>6. 响应接口</h3>
<p>由于 gin 框架的响应依赖于 *gin.Context</p>
<p>所以封装了一个结构体做这件事,但是需要把 *gin.Context 作为参数传入</p>
<p>详见 app/common/ginctx.go</p>
<pre><code>commonGin := common.Gin{Ctx:c} // 注入 *gin.Context
commonGin.Fail(common.WrongFormat,"格式错误") // 响应错误
commonGin.Success(exampleOneRespData{[]string{}, -1}) // 响应 success</code></pre>
<h3>7. 中间件设置</h3>
<p>在 app\middleware 下新建</p>
<p>然后在 app/route.go 中使用即可</p>
<pre><code> app\middleware
func Recover() gin.HandlerFunc{
return func(c *gin.Context) {
// 定义处理过程
c.Next()
}
}
app/route.g
router := gin.Default()
//add middleware to deal panic
router.Use(middleware.Recover()) // 使用办法 1,全局生效
demo := router.Group("/demo",middleware.Recover()) // 使用办法 2,特定路由生效
{
demo.POST("/example1", controller.ExampleOne)
}
return router.Run(Listen)
</code></pre>
<h3>8. 配置读取</h3>
<p>固定的配置比如 redis 的配置放在 app/config/config.json</p>
<p>要经常动态变化的配置建议使用缓存作为配置</p>
<h3>9. 初始化(注入)某些服务</h3>
<p>在app/cmd/command.go 的 startService 中初始化</p>
<h3>10. 日志打印</h3>
<p>直接调用 common.Log (打印在根目录下的 log 文件)
这个日志组件暂时只是把 debug 和 info 记在一个文件,把 warn 和 error 记在一个。暂时只用于系统默认记录
todo 可以再封装一个用于记录业务的,分文件夹的 log 助手</p>
<pre><code>common.Log.Error()
</code></pre>
<h3>11. 设置跨域</h3>
<p>todo 使用中间件</p>
<pre><code>func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin")
if origin != "" {
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
c.Header("Access-Control-Allow-Credentials", "true")
}
c.Next()
}
}</code></pre>
<h3>12. 单元测试(办法测试)</h3>
<p>todo 待研究</p>
<h3>13. redis key</h3>
<p>放在 app/rediskey</p>
<pre><code>const ListKey = "z:set:template:article:list:"
const ArticleDetails = "h:template:article:details"
more 。。。。
</code></pre>
<h3>14. 响应状态码</h3>
<p>放在 app/common/errorcode.go</p>
<pre><code>// 通用的业务错误码
const (
WrongParam = 40001
WrongFormat = 40002
AccessDenied = 40003
SessionExpired = 40004
WrongsProtoCode = 40005
UnknownError = 40006
ThirdApiError = 40007
InvalidRequest = 40008
NotFound = 40009
Exist = 40010
)
more 。。。。
</code></pre>
<h3>15. 结构体定义</h3>
<ul>
<li>
<p>request 参数结构体</p>
</li>
<li>
<p>response 结构体</p>
</li>
<li>存储 redis 返回结果的结构体</li>
</ul>
<p>暂定放在 app/structs</p>
<p>可能还有其他实践,再定。</p>
<h3>16. 依赖引入办法</h3>
<p>有两种方式,暂定用 go mod 的方式,详见项目下的 go.mod
<img src="https://www.showdoc.cc/server/api/common/visitfile/sign/7fa84146b43d77e4b75dbc2ee44dbe5c?showdoc=.jpg" alt="" /></p>
<h3>17. redis 池的配置问题 (重点)</h3>
<p>理解下面几个的作用 <a href="https://www.jianshu.com/p/d36ab0c1e465">https://www.jianshu.com/p/d36ab0c1e465</a></p>
<p><img src="https://www.showdoc.cc/server/api/common/visitfile/sign/02a933f0f7302988f73e2ae83f6ccfcb?showdoc=.jpg" alt="" /></p>
<p><a href="https://www.showdoc.cc/344608763388140?page_id=3223718891102663">https://www.showdoc.cc/344608763388140?page_id=3223718891102663</a></p>
<h3>18. 前台走完流程需要的接口:</h3>
<ul>
<li>首页 (/api/template/home_page_list) // ok,差地理位置</li>
<li>详情页 (/api/template/details_list_new) // ok</li>
<li>分享弹窗 (api/template/common_pool) // ok</li>
<li>
<p>轮播 (/api/template/v2/proto_broadcast_list) // ok</p>
<hr />
</li>
<li>
<p>用户初始化 (/api/user/make_session) // ok</p>
<hr />
</li>
<li>流量分发 (/api/distribute/info)</li>
<li>
<p>流量分发上报 (/api/distribute/report)</p>
<hr />
</li>
<li>作者信息 (/api/author/get_info)</li>
<li>
<p>作者文章 (/api/author/get_article_list)</p>
<hr />
</li>
<li>获取赞赏列表 (/api/reward/getRewardList)</li>
<li>调起支付接口 (/api/reward/toReward)
省略.....</li>
</ul>
<h3>其他 ing</h3>
<p>程序的初始化过程</p>
<p>mysql 的封装、</p>
<p>文件名的定义规范等等。。。。</p>