总结一下最近 beego 开发遇到的坑

总结一下最近 beego 开发遇到的坑

编程那点事 随便写写 Go 1607 字 / 3 分钟

最近一直在写 Apicon 的主站,目前虽然还有很多功能没有写完,不过先配好了 Drone 直接上线了。 因为我的前端实在是太菜了,Vue 写到后面暴露出了很多问题;索性就放弃了之前定下的前后端分离,直接用 beego 开始写 MVC 了。

推翻之前所做的,确实需要一定勇气。不过就目前的情况看来,我还是挺满意这个决定的。 期间遇到了不少问题以及坑,这里总结一下吧。

自定义错误页

自定义诸如 404、501 等状态码的报错页,在 beego 中,是通过指定ErrorController来实现的。

beego.ErrorController(&controllers.ErrorController{})

之后在ErrorController控制器中,编写Error404 Error501等方法即可:

func (this *ErrorController) Error404(){
	this.TplName = "error/404.tpl"
}

同时,可以使用 this.Abort("401")来终止执行并跳转到指定的状态码错误页。 除了状态码外,还有ErrorDb()方法,来处理当数据库发生错误时的情况。

beego 的配置文件

在使用 gin 框架进行开发的时候,遇到外部需要载入的配置,往往都会安装toml的包解析toml文件,从中读取配置。而在 beego 中,我是将诸如数据库信息、七牛云的 Key,都写在了 beego 自带的app.conf文件中。 这样读取配置项将变得十分方便:

beego.AppConfig.String("QiniuAccessKey")

但同时也要注意我们自己定义的配置的 key,不要跟 beego 自带的配置项重复了。

上传文件到七牛云时证书错误

Apicon 上用户可以上传 Api 的封面图片,本来是想放到第三方图床的,但是这样不带 CDN 加速。最后决定全部扔到七牛云上。 因为七牛云本身的技术栈就是 Golang,因此对于 Golang 提供了很强大的 sdk。我们直接根据官方文档把 sdk 的包拉下来就能用了。 Apicon 中相关文件上传的代码如下,整个过程其实跟 Amazon S3 的 Go sdk 十分相似。

key := "cover/" + randstr.String(16) + ext
	putPolicy := storage.PutPolicy{
		Scope: "xxxxx",
	}
	mac := qbox.NewMac(beego.AppConfig.String("QiniuAccessKey"), beego.AppConfig.String("QiniuSecretKey"))
	upToken := putPolicy.UploadToken(mac)

	cfg := storage.Config{}
	cfg.Zone = &storage.ZoneHuanan		// 空间对应的机房
	cfg.UseHTTPS = false		// 是否使用https域名
	cfg.UseCdnDomains = true	// 上传是否使用CDN上传加速
	formUploader := storage.NewFormUploader(&cfg)

	ret := storage.PutRet{}
	putExtra := storage.PutExtra{}
	err = formUploader.Put(context.Background(), &ret, upToken, key, file, dataLen, &putExtra)
	if err != nil {
		...
	}
有坑注意! 这里有两个小坑需要注意。 第一是上传的空间所对应的机房,注意不要搞错地区了。不然会报一个请求 URL 错误。 第二是我在服务器的生产环境上运行时,上传请求会报错说无法验证 HTTPS 证书。不知道是不是我 Alpine 镜像的问题。上网找了下并且翻看了 GitHub issues,好像没有人遇到过类似的问题。我最后的解决方法是设置`cfg.UseHTTPS = false`,即不使用 HTTPS 域名上传。直接走 HTTP 也就避免了证书的问题。

Dockerfile 导致的无法找到模板文件以及静态资源

使用 Drone 部署上线后,访问时会报错无法找到views文件夹下的模板文件。这是因为我最初 Dockerfile 是这样的:

...
ADD . /home/app/
ENTRYPOINT ["/home/app/apicon-mvc"]
...

站点的可执行文件是放在/home/app下的,容器的入口填写的路径是/home/app/apicon-mvc。实际上,这是在/目录下执行的这一条命令,beego 会从在运行它的目录下去寻找views文件,而不是从它本身二进制文件所在的目录下。 因此在这里我们需要在 Dockerfile 里设置WORKDIR,即相当于切换当前的工作目录。这样 beego 就可以通过相对路径找到我们的文件了。 修改后的 Dockerfile 是这样的:

...
ADD . /home/app/
WORKDIR /home/app
ENTRYPOINT ["apicon-mvc"]
...

生产环境部署注意

虽然这不是什么难点,但毕竟这是我第一次亲自做。 因此记录一下部署到生产环境下需要注意的地方吧。 首先,为了使得本地的正常测试,conf/app.conf可以填写本地环境配置,或者直接给gitignore掉。 在生产环境中,将宿主机中的app.conf映射进容器内,实现配置的替换。

docker run -dt --name apicon-site -p xxxxx:xxxxx -v /home/app/apicon-mvc/conf:/home/app/conf $DOCKER_REGISTRY/xxxx/xxxx:latest

对于 beego 而言,记得要在app.conf里设置runmode = dev以开启生产环境。之后所有的报错均以 500 的状态显示,不再会出现开发环境下的报错信息以及调用堆栈。 同时在生产环境下,也不再会有模板文件的热更新,模板文件不再会加载多次。

TODO

接下来打算解决的是如何优雅的进行热更新。gin 的文档里是有介绍如何优雅地停止重启应用的,然而 beego 并没有。我比较担心的是 beego 在重启应用后,其之前的 Session 将全部失效。也就是用户会被强行登出。不知道有无好的解决方法。

看到 Apicon 一点一点逐渐有了雏形,真的好开心啊!