beego搭建博客遇到的问题

beego,jQuery,bootstrap踩坑集锦

Posted by John Mactavish on August 13, 2019

前言

  我开始使用beego搭建个人博客了,简单看了beego的源码和快速入门,表示beego真是awesome。代码写得非常好,很值得学习。结合beego官方的开发文档和示例项目开源代码学起来很舒服。但是还是踩了坑,特别写博客记录下来,持续更新。

beego读取app.conf和bee run的应用名

起因

写modles模块的数据库,写了一小部分,进行单元测试时,显示

register db default, sql: unknown driver “” (forgotten import?)

但是我的sqlite3驱动是已经导入了的。

import _“github.com/mattn/go-sqlite3”

过程

判断是注册数据库时出的错,打印中间信息

driverName := beego.AppConfig.String(“driverName”) fmt.Println(beego.AppConfig.String(“appname”)) orm.RegisterDriver(driverName, orm.DRSqlite)

输出为空,但是配置文件app.conf上确实写了

driverName = sqlite3

改成

driverName = “sqlite3”

无果,改为打印配置文件上原来就有的appname,仍然为空。证明conf文件字符串不需要双引号,同时说明是没有读取到配置文件。

查看beego的config.go,它的init函数在工作目录或app目录查找app.conf并解析到AppConfig中。修改config.go来打印工作目录,显示为MyBlog/models目录。

运行bee run,发现应用文件名为models,原来我的终端工作目录切换到了MyBlog/models目录。bee run在应用的子目录时居然是用当前目录作为应用名。同时程序试图在MyBlog/models/conf目录而非MyBlog/conf目录查找配置文件。终端切换到应用源代码根目录,问题解决。

启示

注意程序的工作目录,比如go run把二进制文件放在系统的临时文件夹中然后运行,有时也会出错。

fmt.Println和println的区别

起因

使用 Go 内置的println不用导入新的包,我用它来打印函数返回值,编译报错

multiple-value (&unit).Insert() in single-value context

过程

原因是函数有多个返回值但是使用环境是处理单值的。换成fmt.Println就行了。原来前者更加强大,可以处理多个值。

启示

上网查询可知,后者是调试工具,因为它不需要依赖,很方便。但是前者才是你进行标准输出的正确方案。同时,如果在使用后者时出现了问题,不妨把它换成前者试试。

jQuery提交表单的问题

起因

设计注册页面做测试时,后台数据库没有正常载入提交的信息。在POST的controller中打印调试信息,发现没有执行POST方法。bee工具也确实没有显示POST信息。

过程

在浏览器调试模式的network选项卡下找到request,提交信息的url没错,但是显示的是GET。同时前端也没有验证表单信息,确定是处理表单的jquery没有执行。

注:在调试模式network选项卡中可以勾选Disable cache来禁用单个网站的缓存,对于网页调试很有帮助,避免缓存引起的坑,建议勾选上。 在html中给form标签直接加上method=”POST”的属性,重新运行,提交表单后崩溃。显示 Handler crashed with error can’t find templatefile in the path:views/registercontroller/post

但是后台数据库确认插入新数据成功。说明POST方法被执行,数据库有关的函数正常。但是程序试图请求一个模板文件,因为没有明确指明,按照beego默认的路径寻找

c.TplName = strings.ToLower(c.controllerName) + “/” + strings.ToLower(c.actionName) + “.” + c.TplExt

这就奇怪了,为什么POST要请求模板页面?
按照网上的方法在配置文件中修改

autorender = false

关闭模板文件自动渲染,结果整个页面都无法加载,确认这是开发api的选项,不能解决我的问题。
在配置文件中修改

copyrequestbody = true

它会直接将服务器的request显示在浏览器页面上。但是还是会崩溃。

博客写到这里时我突然想到服务器在验证信息不对时会返回request,为什么验证信息可以注册时会崩溃。于是发现在POST方法中验证信息可以注册的分支中我忘记写

c.ServeJSON()

来发送数据了。没有手动响应,beego就自己直接去找模板文件了。

这样,一个问题解决了。但是jQuery的问题还没有处理。

javascript导入的顺序

起因

我决定自己写jQuery的表单验证。同时,我决定使用bootstrap来布局,我在网上看到bootstrap有嵌入自己的表单验证。所以我决定使用这个。导入bootstrap后写好自己的表单验证脚本。运行时浏览器调试模式报错

TypeError: $(…).bootstrapValidator is not a function

在stackoverflow上发现了同样的问题。最佳回答指出它可能源于:

  1. jQuery库未导入
  2. jQuery库重复导入
  3. 使用jQuery库的脚本在jQuery库之前导入

他指出,javascript在浏览器中的加载顺序和导入顺序相同。所以要根据依赖关系确定导入顺序。一般的顺序是:

  1. jQuery库
  2. 框架库(bootstrap等)
  3. 自己写的脚本

但是我的问题并不在于此。而是bootstrapValidator并不是bootstrap.min.js里面自带的,而是需要单独导入bootstrapValidator.min.js和bootstrapValidator.min.css,我没有导入,jQuery当然找不到函数了。

ajaxSubmit函数不执行

起因

在注册逻辑的基础上写登录界面和登录的表单验证,运行时发现表单验证正常进行,但是提交函数没有反应。浏览器调试模式反应前端表单未发出。

过程

解决问题花了很长时间,但是长话短说,是因为提交的button在html中位置没有放对。bootstrap自带的表单验证需要按照固定的结构寻找表单和提交按钮。

启示

其实我一开始就发现button位置没有布局好,注册界面上button和表单绑定得很好,登陆界面却明显不受样式控制。使用框架时样式可能不仅仅控制外观,还会影响它绑定的脚本函数。前端调试要注意检查这个。

bootstrap版本不对

起因

我粘贴以前的导航栏布局,结果显示异常,没有自适应,导航一直处于折叠状态。浏览器显示bootstrap样式是加载了的,而且显示的确实不是默认html样式。所以怀疑是脚本冲突,导致折叠效果失效和样式错误;或者是Go的html模板出错。

过程

我注释了脚本导入,没有任何变化。不使用Go模板,直接使用一整个html文件;还是没有用。
找到bootstrap菜鸟教程,在导航栏的那一节的在线尝试中粘贴自己的html,显示正常。把在线尝试上原来有的html粘贴到自己的工程上,bee run运行。正常。逐步更换为自己的html,观察从什么地方开始出错。只切换为自己的navbar模板,正常;只切换为自己的head模板,异常。说明是head写的不对。只切换head脚本导入,正常;只切换css导入,异常。
这就奇怪了,bootstrap是官网下的呀。突然想起来我用的是bootstrap 4.0.0版本,上网一查,果然导航栏写法不一样。菜鸟教程上用的是CDN加速,引用的是网上的bootstrap 3,所以正常。

启示

我开发一直都很激进,用的东西一般都是最新版。在这种情况下应当注意版本问题,不同版本可能相差很大。在网上搜索东西也应当加上版本号,并注意版本号,这样才能减少踩坑。

网站二级目录问题(我也不是很确定)

经过一番探索,确定beego的多级目录大概是这样的。
controller模块里面的TplName值是html文件在服务器Web应用里的地址,浏览器解析html头部的CSS和js的相对地址(src值不以斜杠开头)时,则会在当前网站目录下寻找。比如

src=”static/css/mystyle.css”
当前网站目录user/view

那么浏览器会请求”user/static/css/mystyle.css”。按照beego的处理逻辑,如果请求的是网站根目录下的static,它会定位到应用根目录下的static,否则会在html文件所在目录下寻找static。实测建立软链接不行,要么换html头部的文件src为相对地址和CDN加速网址,要么修改router模块放弃二级目录。 *** 更新,我今天看了开发文档。是这样的,可以通过在beego.Run()之前添加静态文件注册函数

beego.SetStaticPath(“/article/static”, “static”)

来把浏览器对”/article/static”的请求重定向到应用根目录下的”static”文件夹,默认注册了

beego.SetStaticPath(“/article/static”, “static”)

这样一来,二级目录问题基本解决了,可以在router.go中注册二级目录了。

bee命令行没有监控的显示

起因

bee启动应用会建立本地监听,把http的请求情况打印在终端上,对于后端的调试非常方便。但是,有的时候会突然没有显示。

过程

我不断重试,没有效果。最后关闭了终端,在任务管理器中终止了wsl和bee的进程。(好像有两个bee的进程,是这个的缘故吗?)然后重新启动wsl,一切又正常了。(虽然我还不知道原因,但是猜测可能是终端输出重定向了或者怎么的)

启示

wsl的终端出现玄学问题时,不妨打开任务管理器全部关掉再重试。

文件下载的大坑

起因

按照我的设计,添加博客文章时直接拖拽markdown文件上传,不用什么在线编辑。先不试拖拽,把文件上传搞定再说。网上说表单提交和文件上传不可以同时进行。但是,我又找到了解决方法。使用FormData,把文件和表单一起放进去,就可以通过ajax发送给后端。然后我发现后端没有收到文件,查看前端。network选项卡下对应的POST大小只有220B,而且source下显示为空。

过程

我百思不得其解,又研究了beego接受文件的两个api,GetFile和SaveTofile。最后通过提取GetFile返回的文件的byte,将其用string()函数处理并打印才发现其实文件已经收到了。
最后在beego开发文档的api文档中找到了可能的原因。上面用的是相对于应用根目录的相对地址”static/upload”,我试了一下,真的可以。但是试图把文件写进home目录等地方就毫无反应。看起来后端的问题是文件的读写权限;前端的问题是长数据根本就不显示,导致我误判了,以为问题出在前端。

启示

其实开发文档就可以避坑了,可惜我一开始遇到问题时没有第一时间对照开发文档寻找问题。

Go包的问题

起因

controllers模块中有多个有关article的处理逻辑,为了不让controllers文件夹显得臃肿,我把包含有关article的处理逻辑的文件全部放在一个子目录article下。编译时router.go报错包名出了问题。

过程

上网搜索得知,Go的package名字与文件夹名不一定需要相同(虽然建议相同)。导入包时包由导入路径和包名同时确定、标识,所以同一个包的文件必须放在同一个文件夹下,子文件夹是不行的。所以”controllers/article”下的controllers包和”controllers”下的controllers包是两个不同的包。只能将”controllers/article”下的包重新取一个名字再由其他包通过新名字导入,重新取名字是为了防止和controllers包重名,毕竟使用的时候是用的包名。但是它仍然属于 MVC 中的 C 模块。

同时,一个文件夹下只可以有一个包,main包是特殊的,它是入口。

启示

所以你可以写一个toolbox包,再创建一个子目录”toolbox/example”。子目录里面写一些demo,demo可以有main函数。保持文件夹逻辑合理的同时demo里面的东西不会污染toolbox包。

html模板解析失败

这个体现出Go编译器的提示不是特别的友好,主要就是

template.go:176 parse template err: article/view.html template: article/view.html:21: unexpected EOF

其实问题是模板的忘记加了,这提示真的是一点帮助都没有啊。

conf配置文件语法

这是读取app.conf中的文件保存路径时发现的问题。也不知道是conf配置文件语法本身要求的,还是beego的配置文件读取模块不完善。
字符串(比如说文件路径)不需要也不能加双引号,读取配置时会把双引号也读取进去。同时注释应当独占一行,以‘#’开头。而配置参数后面的‘#’开头的注释也会被当成配置的字符串参数。

参考

介绍bootstrapValidator
title


最后附上GitHub:https://github.com/gonearewe