多个response.WriteHeader调用

huangapple go评论91阅读模式
英文:

Multiple response.WriteHeader calls

问题

我是新手,对于渲染模板有困难。

这是我用来生成模板的函数:

base.html

// 根据给定的名称、模板定义和数据对象渲染模板
func renderTemplate(w http.ResponseWriter, name string, template string, viewModel interface{}) {
    // 确保模板在映射中存在
    tmpl, ok := templates[name]
    if !ok {
        http.Error(w, "模板不存在。", http.StatusInternalServerError)
    }
    err := tmpl.ExecuteTemplate(w, template, viewModel)
    if err != nil {
        log.Printf("模板错误。")
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

func EditNote(w http.ResponseWriter, r *http.Request) {
    //var viewModel models.EditChnl
    vars := mux.Vars(r)
    //ch := bson.M{"id": "Ale"}
    title := vars["title"]
    log.Printf("%v\n", title)
    session, err := mgo.Dial("localhost")
    if err != nil {
        panic(err)
    }
    defer session.Close()
    session.SetMode(mgo.Monotonic, true)
    c := session.DB("tlgdb").C("chnls")
    log.Printf("title is %s \n", title)
    var result []models.Chnl
    err = c.Find(bson.M{"title": "xxx"}).All(&result)
    log.Printf("%v\n", result)

    if err != nil {
        log.Printf("文档未找到")
        log.Fatal(err)
        return
    }
    renderTemplate(w, "edit", "base", result)
}

以下是模板:

{{define "base"}}
<html>
  <head>
    {{template "head" .}}
  </head>
  <body>
  
    {{template "body" .}}
 
  </body>
</html>
{{end}}

edit.thml

```html
{{define "head"}}<title>编辑笔记</title>{{end}}
{{define "body"}}
<h1>编辑笔记</h1>
<form action="/chnls/update/{{.Title}}" method="post">
<p>标题:<br> <input type="text" value="{{.Title}}" name="title"></p>
<p>描述:<br> <textarea rows="4" cols="50" name="description">{{.Description}}</textarea> </p>
<p><input type="submit" value="提交"/></p>
</form>
{{end}}

要渲染的对象是:

type Chnl struct {
    Id          bson.ObjectId `json:"id" bson:"_id,omitempty"`
    Title       string
    Description string
    CreatedOn   time.Time
    Creator     string
    Visits      int
    Score       int
}

我尝试渲染的对象在mongodb中存在,并且我可以在控制台中打印出来:

[{ObjectIdHex("56cc4493bc54f4245cb4d36b") sometitle blabla 2016-02-23 12:37:55.972 +0100 CET blabla 0 0}]

然而,我得到了以下错误:

模板错误
http: 多次调用response.WriteHeader

我想知道这里出了什么问题,如何修复?

英文:

I am new to go and have difficulty rendring templates.

Here is my functions that are to generate template:

base.html

//Render templates for the given name, template definition and data object
func renderTemplate(w http.ResponseWriter, name string, template string, viewModel interface{}) {
	// Ensure the template exists in the map.
	tmpl, ok := templates[name]
	if !ok {
		http.Error(w, &quot;The template does not exist.&quot;, http.StatusInternalServerError)
	}
	err := tmpl.ExecuteTemplate(w, template, viewModel)
	if err != nil {
    log.Printf(&quot;temlate error here&quot;)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}


 func EditNote(w http.ResponseWriter, r *http.Request) {
    //var viewModel models.EditChnl
  	vars := mux.Vars(r)
    //ch := bson.M{&quot;id&quot;: &quot;Ale&quot;}
  	title := vars[&quot;title&quot;]
    log.Printf(&quot;%v\n&quot;, title)
    session, err := mgo.Dial(&quot;localhost&quot;)
    if err != nil {
      panic(err)
    }
        defer session.Close()
        session.SetMode(mgo.Monotonic, true)
        c := session.DB(&quot;tlgdb&quot;).C(&quot;chnls&quot;)
        log.Printf(&quot;title is %s \n&quot;, title)
        var	result  []models.Chnl
        err = c.Find(bson.M{&quot;title&quot;: &quot;xxx&quot;}).All(&amp;result)
        log.Printf(&quot;%v\n&quot;, result)

        if err != nil {
          log.Printf(&quot;doc not found&quot;)
          log.Fatal(err)
          return
        }
  	renderTemplate(w, &quot;edit&quot;, &quot;base&quot;, result)
}

And here are the templates:

{{define &quot;base&quot;}}
&lt;html&gt;
  &lt;head&gt;
    {{template &quot;head&quot; .}}
  &lt;/head&gt;
  &lt;body&gt;
  
    {{template &quot;body&quot; .}}
 
  &lt;/body&gt;
&lt;/html&gt;
{{end}}

edit.thml

{{define &quot;head&quot;}}&lt;title&gt;Edit Note&lt;/title&gt;{{end}}
{{define &quot;body&quot;}}
&lt;h1&gt;Edit Note&lt;/h1&gt;
&lt;form action=&quot;/chnls/update/{{.Title}}&quot; method=&quot;post&quot;&gt;
&lt;p&gt;Title:&lt;br&gt; &lt;input type=&quot;text&quot; value=&quot;{{.Title}}&quot; name=&quot;title&quot;&gt;&lt;/p&gt;
&lt;p&gt;Description:&lt;br&gt; &lt;textarea rows=&quot;4&quot; cols=&quot;50&quot; name=&quot;description&quot;&gt;{{.Description}}&lt;/textarea&gt; &lt;/p&gt;
&lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;submit&quot;/&gt;&lt;/p&gt;
&lt;/form&gt;
{{end}}

The objects to render are:

type Chnl struct {
	Id    bson.ObjectId `json:&quot;id&quot;  bson:&quot;_id,omitempty&quot;`
	Title       string
	Description string
	CreatedOn   time.Time
	Creator		string
	Visits	int
	Score		int
}

The object that I'm trying to render exists in mongodb and I can print it out in console:

[{ObjectIdHex(&quot;56cc4493bc54f4245cb4d36b&quot;) sometitle blabla 2016-02-23 12:37:55.972 +0100 CET blabla 0 0}]

However I get this error:

temlate error here
http: multiple response.WriteHeader calls

I'm wondering what is wrong here and how to fix it?

答案1

得分: 2

根本问题在于你将 Chnl 的切片传递给了模板:

var result []models.Chnl
// ...
renderTemplate(w, "edit", "base", result)

而在 renderTemplate() 函数中,viewModel 参数的值将是 result

在你的模板中,你引用了点号的字段,就好像它是一个 Chnl 值,而不是它的切片:{{.Title}}。因此,第一次尝试解析它将失败。

记录错误是有用的,所以将你的日志记录更改为打印实际的错误,而不仅仅是通用的错误信息:

log.Printf("模板错误:%v", err)

这将得到以下结果:

> 2016/02/24 14:57:09 模板错误:template: edit.html:4:30: 在 <.Title> 处执行 "body":无法在类型 []main.Chnl 中评估字段 Title

我认为你只想传递一个 Chnl 值,而不是它们的切片。在 EditNote() 函数中:

if len(result) > 0 {
    renderTemplate(w, "edit", "base", result[0])
}

另外,要知道 http.Error() 会将内容写入响应。这意味着你不能在响应中写入其他的头部值。通常情况下,当你在处理程序中调用 http.Error() 时,应该立即返回而不对响应做任何操作:

if !ok {
    http.Error(w, "模板不存在。", http.StatusInternalServerError)
    return // 注意这个返回语句
}

类似地,在所有的 http.Error() 调用之后插入一个 return 语句。你可以进行一些清理操作,但在 http.Error() 之后不应该再操作响应。

英文:

The root problem is that you pass a slice of Chnl to the template:

var result  []models.Chnl
// ...
renderTemplate(w, &quot;edit&quot;, &quot;base&quot;, result)

And inside renderTemplate() param value of viewModel will be result.

And in your templates you refer to fields of the dot like if it would be a Chnl value and not a slice of it: {{.Title}}. So the first attempt to resolve it will fail.

Logging the errors is useful, so change your logging to also print the actual error, not just a generic error:

log.Printf(&quot;Temlate error here: %v&quot;, err)

Which results in:

> 2016/02/24 14:57:09 Temlate error here: template: edit.html:4:30: executing "body" at <.Title>: can't evaluate field Title in type []main.Chnl

I think you just want to pass 1 Chnl value and not a slice of them. In EditNote():

if len(result) &gt; 0 {
    renderTemplate(w, &quot;edit&quot;, &quot;base&quot;, result[0])
}

Next, know that http.Error() writes content to the response. This means you cannot write further header values to the response. Usually when you call http.Error() in your handler, you should return without doing anything with the response:

if !ok {
    http.Error(w, &quot;The template does not exist.&quot;, http.StatusInternalServerError)
    return // NOTE THIS RETURN
}

Similarly, after all your http.Error() call insert a return. You may do some cleanup, but response should not be touched after http.Error().

huangapple
  • 本文由 发表于 2016年2月24日 21:09:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/35603131.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定