beego自定义模板函数须在beego.run()前注册,签名限单返回值,str2html非xss防护方案,date函数已移除需用dateformat,substr按rune安全截中文,错误默认静默。

beego自定义模板函数必须在beego.Run()之前注册
所有自定义模板函数都得在beego.Run()调用前通过beego.AddFuncMap()注册,否则模板里调用会静默失败或报template: xxx: function "xxx" not defined错误。
常见错误是把AddFuncMap写在main()末尾、或者放在某个init()函数里但执行时机晚于Run()。正确位置是beego.Run()正上方,且确保该函数已声明(不能是未导出的局部函数)。
- 函数签名必须是
func(inputType) outputType或func(inputType) (outputType),返回值只能有一个(或带命名) - 支持多参数的函数需用结构体或
interface{}包装,模板中不支持直接传多个参数 - 若函数有副作用(如查DB),要注意并发安全——模板渲染可能并发执行,避免共享可变状态
str2html和htmlquote不是万能的XSS防护方案
str2html只是取消HTML转义,把字符串当原始HTML输出;htmlquote仅做基础字符替换(→<code><等),都不校验标签合法性或过滤script、onerror等危险属性。
如果你从用户输入中取内容并用{{.UserInput | str2html}}渲染,等于直接执行任意HTML——这是典型XSS入口。真正需要渲染富文本时,应先用html2str剥离标签,或用第三方库(如bluemonday)白名单过滤后再str2html。
- 不要对未清洗的用户数据用
str2html,哪怕只显示一段简介 -
htmlquote适合输出到HTML属性值中(如title="{{.Title | htmlquote}}"),但对innerHTML场景无效 - 模板里混用
str2html和html2str容易绕过预期:比如{{.HtmlContent | html2str | str2html}}仍可能残留img标签的onload
时间格式化别硬套PHP风格的date函数
beego内置的date函数模仿PHP语法(如{{date .Ts "Y-m-d H:i:s"}}),但它在v2+版本中已被移除,官方源码里早已不存在。现在可靠的方式只有两种:dateformat(Go原生格式)或自定义函数。
Go的时间格式化字符串是“参考时间”2006-01-02 15:04:05 MST,每个数字对应固定含义(如06是年,01是月),不是占位符。写成"Y-m-d"会直接输出字面量Y-m-d,而不是你想要的日期。
- 用
{{dateformat .Time "2006-01-02 15:04:05"}}最稳妥,兼容所有beego版本 - 若需支持时区转换,
dateformat不处理,得在controller里用time.In()预转换好再传入模板 - 自定义
formatTime函数时,注意time.Unix()第二个参数是纳秒,传0即可,别错写成time.Unix(ts, ts%1e9)
中文截取用substr比原生[start:end]安全
Go字符串底层是UTF-8字节数组,直接用.Str[0:10]可能在中文中间截断,导致乱码或模板解析失败。beego内置substr函数内部用utf8.RuneCountInString计数,按rune而非byte切分,天然支持中文。
但要注意:substr第三个参数是length(rune个数),不是结束位置。例如{{substr .Title 0 15}}取前15个汉字,而{{substr .Title 5 15}}是从第5个rune开始取15个,不是取索引5~15之间的子串。
- 如果要加省略号,得自己拼接:
{{substr .Title 0 15}} {{if gt (len .Title) 15}}…{{end}} -
substr对空字符串、nil、超长索引返回空字符串,不会panic,但也不会报错提示——得靠日志或测试覆盖边界情况 - 若需更复杂逻辑(如保留完整词、按标点截断),还是得写自定义函数,别硬塞进
substr参数里
Debug,或在自定义函数里加log.Printf,否则一个类型不匹配就卡在页面某块空白处,找不到源头。











