【遇到一个怪异的问题】使用embed来加载模版,只要写在init()函数中就会导致HTTP服务出错
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
经过反复测试,只要换一个写法就能开启/重现这个怪异的问题。
请看出现异常的代码:
//go:embed index.html
var indexFileTemplate string
var indexTempate = template.New("index")
//go:embed mysql_data_source.html
var mysqlDataSourceFileTemplate string
var mysqlDataSourceTempate = template.New("mysql_data_source")
// var mysqlDataSourceTempate = template.Must(template.New("mysql_data_source").Parse(mysqlDataSourceFileTemplate))
func init() {
indexTempate = template.Must(indexTempate.Parse(indexFileTemplate))
mysqlDataSourceTempate = template.Must(indexTempate.Parse(mysqlDataSourceFileTemplate))
}
使用上述的代码,gin框架中访问首页,在执行模版的时候报这样的错误:
template: index:9:49: executing "index" at <.Name>: can't evaluate field Name in type *page.templateParam
我在index.html中没有{{.Name}},只在mysql_data_source.html中有使用。不管怎么样,我访问首页,和另一个页面没关系鸭!
换个写法就能正常打开首页:
//go:embed index.html
var indexFileTemplate string
var indexTempate = template.New("index")
//go:embed mysql_data_source.html
var mysqlDataSourceFileTemplate string
var mysqlDataSourceTempate = template.New("mysql_data_source")
var mysqlDataSourceTempate = template.Must(template.New("mysql_data_source").Parse(mysqlDataSourceFileTemplate))
func init() {
indexTempate = template.Must(indexTempate.Parse(indexFileTemplate))
//mysqlDataSourceTempate = template.Must(indexTempate.Parse(mysqlDataSourceFileTemplate))
}
简直是无语了……
猜测可能的原因:
embed对应的字符串的加载,是比init()函数还要晚的。当init函数执行的时候,embed的字符串还没加载,这样就导致了模版解析出错。然而,template.Must()并不会导致panic,只是默默地记录下了这个错误。等到模版真正被使用的时候,抛出模版加载期导致的错误,进而出现上述的现象。解决办法就是不要在init函数中写模版加载的代码。
已经把这个问题提到了官方:https://github.com/golang/go/issues/56952
11-29补充:
已经得到了官方的回答,原因还是赋值语句和init()函数的先后顺序导致的。
我自己的代码,假定赋值先执行,然后init()函数再执行。
但是,如果init()先执行,而赋值后执行,就会导致indexTempate对象处于未初始化的状态。
因此,解决办法是不要假定初始化执行的顺序,统一只在一个地方初始化。
【遇到一个怪异的问题】使用embed来加载模版,只要写在init()函数中就会导致HTTP服务出错的更多相关文章
- 一个页面从输入URL到页面加载显示完成,这个过程都发生了什么?
对于网址栏的URL不同的操作方式有不同的加载资源.获取数据的方式,下面的详细过程针对"在地址栏输入URL,按enter(回车)键加载资源"此种操作方式做解析,其它的方式的过程大同小 ...
- 一个页面从输入url到页面加载显示完成,中间都经历了什么
第一种解释: 一般会经历以下几个过程: 1.首先,在浏览器地址栏中输入url 2.浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容.若没有,则跳到第三步操作. 3 ...
- 一个页面从输入URL到页面加载完成发生了...待细化
一个页面从输入URL到页面加载完成发生了... 1.查找浏览器缓存 2.寻址:DNS解析 查找该域名对应的IP地址, 如果需要重定向(301),则再次发起请求 3. 进行HTTP协议会话 4.客户端发 ...
- JS window对象 返回下一个浏览的页面 forward()方法,加载 history 列表中的下一个 URL。
返回下一个浏览的页面 forward()方法,加载 history 列表中的下一个 URL. 如果倒退之后,再想回到倒退之前浏览的页面,则可以使用forward()方法,代码如下: window.hi ...
- 一个页面从输入URL 到页面加载显示完成的过程中都发生了什么
前端面试/笔试必考问题,越详细越好 先简单得讲: 浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求: 服务器交给后台处理完成后返回数据,浏览器接收文件(HTML.JS.CSS. ...
- Vue-上拉加载与下拉刷新(mint-ui:loadmore)一个页面使用多个上拉加载后冲突问题
所遇问题: 该页面为双选项卡联动,四个部分都需要上拉加载和下拉刷新功能,使用的mint-ui的loadmore插件,分别加上上拉加载后,只有最后一个的this.$refs.loadmore.onTop ...
- android 分享一个处理BaseAdapter,getView()多次加载的方法
一:BaseAdapter介绍 BaseAdapter是listview,gridview等列表,使用的数据适配器,它的主要用途是将一组数据传到ListView.Spinner.Gallery及Gri ...
- SeaJS:一个适用于 Web 浏览器端的模块加载器
什么是SeaJS?SeaJS是一款适用于Web浏览器端的模块加载器,它同时又与Node兼容.在SeaJS的世界里,一个文件就是一个模块,所有模块都遵循CMD(Common Module Definit ...
- 8.一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
注:这题胜在区分度高,知识点覆盖广,再不懂的人,也能答出几句, 而高手可以根据自己擅长的领域自由发挥,从URL规范.HTTP协议.DNS.CDN.数据库查询. 到浏览器流式解析.CSS规则构建.lay ...
- 一个页面从输入URL 到页面加载显示完成,这个过程中都发生了什么?
1.当发送一个URL请求时,浏览器会开启一个线程来处理这个请求,同时在远程DNS服务器上启动一个DNS查询,解析获取网址的IP地址:2.浏览器与远程Web服务器通过TCP三次握手协商来建立一个TCP/ ...
随机推荐
- 火山引擎 DataLeap 通过中国信通院测评,数据管理能力获官方认可!
近日,火山引擎大数据研发治理套件 DataLeap 通过中国信通院第十五批"可信大数据"测评,在数据管理平台基础能力上获得认证. "可信大数据"产品能力 ...
- Solon2 开发之插件,一、插件
Solon Plugin 是框架的核心接口,简称"插件".其本质是一个"生命周期"接口.它可让一个组件类参与程序的生命周期过程(这块看下:<应用启动过程与 ...
- Solon2 开发之IoC,四、注入依赖与初始化
Solon 强调 有克制的注入 + 手动控制 结合的模式.好处是,代码用料少.启动快. Bean 的关键生命节点: 节点 说明 1. Constructor(构造方法) 不支持参数注入 2. @Inj ...
- Solon Aop 特色开发(4)Bean 扫描的三种方式
Solon,更小.更快.更自由!本系列专门介绍Solon Aop方面的特色: <Solon Aop 特色开发(1)注入或手动获取配置> <Solon Aop 特色开发(2)注入或手动 ...
- CentOS 7上安装 Jenkins 2.227 -- yum 方式
CentOS 7上安装 Jenkins 2.227 -- yum 方式 装插件的时候会报版本过低,建议安装 2.346 安装 Jenkins # [root@localhost ~]# ll /etc ...
- 从各方面比较下kafka、activemq、rabbitmq、rocketmq之间的区别
[消息队列]从各方面比较下kafka.activemq.rabbitmq.rocketmq之间的区别 一.单机吞吐量ActiveMQ:万级,吞吐量比RocketMQ和Kafka要低了一个数量级Ra ...
- C#设计模式17——责任链模式的写法
是什么: 责任链模式是一种行为型设计模式,它允许对象组成一个链并依次检查另一个对象是否可以处理请求.如果一个对象可以处理请求,它处理请求,并且负责将请求传递给下一个对象,直到请求被处理为止. 为什么: ...
- Servlet系列:(HttpServletRequest、HttpServletResponse、ServletContext、ServletConfig)详解
HttpServletRequest HttpServletRequest 对象:主要作用是用来接收客户端发送过来的请求信息,例如:请求的参数,发送的头信息等都属于客户端发来的信息,service() ...
- 每天学五分钟 Liunx 0001 | 存储篇:swap
swap swap ,内存交换空间,它是磁盘上的一块空间,主要作用是为了防止物理内存不足. CPU 从内存中读取数据.当内存的空间不足时, CPU 难以读取到数据,导致程序无法正常工作.所以诞生了 s ...
- docker 容器ip查看及 网络配置区别
本文为博主原创,未经允许不得转载: 1. 查看容器ip: 方法一:查看所有容器的ip docker inspect --format='{{.Name}} - {{range .NetworkSett ...
