前言
我开始使用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上发现了同样的问题。最佳回答指出它可能源于:
- jQuery库未导入
- jQuery库重复导入
- 使用jQuery库的脚本在jQuery库之前导入
他指出,javascript在浏览器中的加载顺序和导入顺序相同。所以要根据依赖关系确定导入顺序。一般的顺序是:
- jQuery库
- 框架库(bootstrap等)
- 自己写的脚本
但是我的问题并不在于此。而是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的配置文件读取模块不完善。
字符串(比如说文件路径)不需要也不能加双引号,读取配置时会把双引号也读取进去。同时注释应当独占一行,以‘#’开头。而配置参数后面的‘#’开头的注释也会被当成配置的字符串参数。
参考
最后附上GitHub:https://github.com/gonearewe