多个response.WriteHeader调用

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

Multiple response.WriteHeader calls

问题

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

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

base.html

  1. // 根据给定的名称、模板定义和数据对象渲染模板
  2. func renderTemplate(w http.ResponseWriter, name string, template string, viewModel interface{}) {
  3. // 确保模板在映射中存在
  4. tmpl, ok := templates[name]
  5. if !ok {
  6. http.Error(w, "模板不存在。", http.StatusInternalServerError)
  7. }
  8. err := tmpl.ExecuteTemplate(w, template, viewModel)
  9. if err != nil {
  10. log.Printf("模板错误。")
  11. http.Error(w, err.Error(), http.StatusInternalServerError)
  12. }
  13. }
  14. func EditNote(w http.ResponseWriter, r *http.Request) {
  15. //var viewModel models.EditChnl
  16. vars := mux.Vars(r)
  17. //ch := bson.M{"id": "Ale"}
  18. title := vars["title"]
  19. log.Printf("%v\n", title)
  20. session, err := mgo.Dial("localhost")
  21. if err != nil {
  22. panic(err)
  23. }
  24. defer session.Close()
  25. session.SetMode(mgo.Monotonic, true)
  26. c := session.DB("tlgdb").C("chnls")
  27. log.Printf("title is %s \n", title)
  28. var result []models.Chnl
  29. err = c.Find(bson.M{"title": "xxx"}).All(&result)
  30. log.Printf("%v\n", result)
  31. if err != nil {
  32. log.Printf("文档未找到")
  33. log.Fatal(err)
  34. return
  35. }
  36. renderTemplate(w, "edit", "base", result)
  37. }

以下是模板:

  1. {{define "base"}}
  2. <html>
  3. <head>
  4. {{template "head" .}}
  5. </head>
  6. <body>
  7. {{template "body" .}}
  8. </body>
  9. </html>
  10. {{end}}
  11. edit.thml
  12. ```html
  13. {{define "head"}}<title>编辑笔记</title>{{end}}
  14. {{define "body"}}
  15. <h1>编辑笔记</h1>
  16. <form action="/chnls/update/{{.Title}}" method="post">
  17. <p>标题:<br> <input type="text" value="{{.Title}}" name="title"></p>
  18. <p>描述:<br> <textarea rows="4" cols="50" name="description">{{.Description}}</textarea> </p>
  19. <p><input type="submit" value="提交"/></p>
  20. </form>
  21. {{end}}

要渲染的对象是:

  1. type Chnl struct {
  2. Id bson.ObjectId `json:"id" bson:"_id,omitempty"`
  3. Title string
  4. Description string
  5. CreatedOn time.Time
  6. Creator string
  7. Visits int
  8. Score int
  9. }

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

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

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

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

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

英文:

I am new to go and have difficulty rendring templates.

Here is my functions that are to generate template:

base.html

  1. //Render templates for the given name, template definition and data object
  2. func renderTemplate(w http.ResponseWriter, name string, template string, viewModel interface{}) {
  3. // Ensure the template exists in the map.
  4. tmpl, ok := templates[name]
  5. if !ok {
  6. http.Error(w, &quot;The template does not exist.&quot;, http.StatusInternalServerError)
  7. }
  8. err := tmpl.ExecuteTemplate(w, template, viewModel)
  9. if err != nil {
  10. log.Printf(&quot;temlate error here&quot;)
  11. http.Error(w, err.Error(), http.StatusInternalServerError)
  12. }
  13. }
  14. func EditNote(w http.ResponseWriter, r *http.Request) {
  15. //var viewModel models.EditChnl
  16. vars := mux.Vars(r)
  17. //ch := bson.M{&quot;id&quot;: &quot;Ale&quot;}
  18. title := vars[&quot;title&quot;]
  19. log.Printf(&quot;%v\n&quot;, title)
  20. session, err := mgo.Dial(&quot;localhost&quot;)
  21. if err != nil {
  22. panic(err)
  23. }
  24. defer session.Close()
  25. session.SetMode(mgo.Monotonic, true)
  26. c := session.DB(&quot;tlgdb&quot;).C(&quot;chnls&quot;)
  27. log.Printf(&quot;title is %s \n&quot;, title)
  28. var result []models.Chnl
  29. err = c.Find(bson.M{&quot;title&quot;: &quot;xxx&quot;}).All(&amp;result)
  30. log.Printf(&quot;%v\n&quot;, result)
  31. if err != nil {
  32. log.Printf(&quot;doc not found&quot;)
  33. log.Fatal(err)
  34. return
  35. }
  36. renderTemplate(w, &quot;edit&quot;, &quot;base&quot;, result)
  37. }

And here are the templates:

  1. {{define &quot;base&quot;}}
  2. &lt;html&gt;
  3. &lt;head&gt;
  4. {{template &quot;head&quot; .}}
  5. &lt;/head&gt;
  6. &lt;body&gt;
  7. {{template &quot;body&quot; .}}
  8. &lt;/body&gt;
  9. &lt;/html&gt;
  10. {{end}}

edit.thml

  1. {{define &quot;head&quot;}}&lt;title&gt;Edit Note&lt;/title&gt;{{end}}
  2. {{define &quot;body&quot;}}
  3. &lt;h1&gt;Edit Note&lt;/h1&gt;
  4. &lt;form action=&quot;/chnls/update/{{.Title}}&quot; method=&quot;post&quot;&gt;
  5. &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;
  6. &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;
  7. &lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;submit&quot;/&gt;&lt;/p&gt;
  8. &lt;/form&gt;
  9. {{end}}

The objects to render are:

  1. type Chnl struct {
  2. Id bson.ObjectId `json:&quot;id&quot; bson:&quot;_id,omitempty&quot;`
  3. Title string
  4. Description string
  5. CreatedOn time.Time
  6. Creator string
  7. Visits int
  8. Score int
  9. }

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

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

However I get this error:

  1. temlate error here
  2. http: multiple response.WriteHeader calls

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

答案1

得分: 2

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

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

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

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

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

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

这将得到以下结果:

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

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

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

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

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

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

英文:

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

  1. var result []models.Chnl
  2. // ...
  3. 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:

  1. 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():

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

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:

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

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:

确定