Golang错误处理错误

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

Golang error handling mistake

问题

以下程序是官方教程中的Web服务器的自定义版本,位于此页面。我只修改了save()和loadPage()函数,以便使用jmcvetta的neoism包将页面保存到neo4j中。

  1. // web1 project main.go
  2. package main
  3. import (
  4. "errors"
  5. "fmt"
  6. "github.com/jmcvetta/neoism"
  7. "html/template"
  8. "io/ioutil"
  9. "net/http"
  10. "regexp"
  11. )
  12. type Page struct {
  13. Title string
  14. Body string
  15. }
  16. func (p *Page) save() error {
  17. db, err := neoism.Connect("http://localhost:7474/db/data")
  18. if err != nil {
  19. return err
  20. }
  21. res := []struct {
  22. N neoism.Node
  23. }{}
  24. cq := neoism.CypherQuery{
  25. Statement: "MERGE (n:Page {title: {title}}) ON MATCH SET n.body = {body} RETURN n",
  26. Parameters: neoism.Props{"title": p.Title, "body": p.Body},
  27. Result: &res,
  28. }
  29. db.Cypher(&cq)
  30. return nil
  31. }
  32. func loadPage(title string) (*Page, error) {
  33. db, err := neoism.Connect("http://localhost:7474/db/data")
  34. if err != nil {
  35. return nil, err
  36. }
  37. res := []struct {
  38. Title string `json:"a.title"` // `json` tag matches column name in query
  39. Body string `json:"a.body"`
  40. }{}
  41. cq := neoism.CypherQuery{
  42. Statement: `
  43. MATCH (a:Page)
  44. WHERE a.title = {name}
  45. RETURN a.title, a.body
  46. `,
  47. Parameters: neoism.Props{"name": title},
  48. Result: &res,
  49. }
  50. db.Cypher(&cq)
  51. r := res[0]
  52. if r.Title == "" || r.Body == "" {
  53. return nil, errors.New("Page doesn't exist")
  54. }
  55. return &Page{Title: r.Title, Body: r.Body}, nil
  56. }
  57. func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
  58. p, err := loadPage(title)
  59. if err != nil {
  60. http.Redirect(w, r, "/edit/"+title, http.StatusFound)
  61. return
  62. }
  63. renderTemplate(w, "view", p)
  64. }
  65. func editHandler(w http.ResponseWriter, r *http.Request, title string) {
  66. p, err := loadPage(title)
  67. if err != nil {
  68. p = &Page{Title: title}
  69. }
  70. renderTemplate(w, "edit", p)
  71. }
  72. func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
  73. body := r.FormValue("body")
  74. p := &Page{Title: title, Body: body}
  75. err := p.save()
  76. if err != nil {
  77. http.Error(w, err.Error(), http.StatusInternalServerError)
  78. return
  79. }
  80. http.Redirect(w, r, "/view/"+title, http.StatusFound)
  81. }
  82. func homeHandler(w http.ResponseWriter, r *http.Request) {
  83. body, err := ioutil.ReadFile("home.html")
  84. if err != nil {
  85. http.Error(w, err.Error(), http.StatusInternalServerError)
  86. return
  87. }
  88. fmt.Fprintf(w, "%s", body)
  89. }
  90. func rootHandler(w http.ResponseWriter, r *http.Request) {
  91. http.Redirect(w, r, "/home", http.StatusFound)
  92. }
  93. var templates = template.Must(template.ParseFiles("edit.html", "view.html"))
  94. func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
  95. err := templates.ExecuteTemplate(w, tmpl+".html", p)
  96. if err != nil {
  97. http.Error(w, err.Error(), http.StatusInternalServerError)
  98. }
  99. }
  100. var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
  101. func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
  102. return func(w http.ResponseWriter, r *http.Request) {
  103. m := validPath.FindStringSubmatch(r.URL.Path)
  104. if m == nil {
  105. http.NotFound(w, r)
  106. return
  107. }
  108. fn(w, r, m[2])
  109. }
  110. }
  111. func main() {
  112. http.HandleFunc("/view/", makeHandler(viewHandler))
  113. http.HandleFunc("/edit/", makeHandler(editHandler))
  114. http.HandleFunc("/save/", makeHandler(saveHandler))
  115. http.HandleFunc("/home", homeHandler)
  116. http.HandleFunc("/", rootHandler)
  117. http.ListenAndServe(":8082", nil)
  118. }

我的问题是,在loadPage()函数中,当返回的页面没有内容时,似乎没有返回任何错误,导致处理程序尝试使用空结构执行模板(至少我认为是这样)。
有人看到我哪里做错了吗?

编辑:当我尝试加载一个不存在的页面时,这是输出:

  1. 2014/06/19 23:13:35 http: panic serving 127.0.0.1:60326: runtime error: index out of range
  2. goroutine 5 [running]:
  3. net/http.func·009()
  4. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1093 +0xb1
  5. runtime.panic(0x6d1f20, 0xa977d7)
  6. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/runtime/panic.c:248 +0x11b
  7. main.loadPage(0xc08407a12a, 0x6, 0x332978, 0xaa7560, 0x3)
  8. C:/Users/Nicolas/Go/src/web1/main.go:55 +0x369
  9. main.editHandler(0x332940, 0xc08400b140, 0xc084019750, 0xc08407a12a, 0x6)
  10. C:/Users/Nicolas/Go/src/web1/main.go:72 +0x34
  11. main.func·001(0x332940, 0xc08400b140, 0xc084019750)
  12. C:/Users/Nicolas/Go/src/web1/main.go:121 +0xc9
  13. net/http.HandlerFunc.ServeHTTP(0xc084024ae0, 0x332940, 0xc08400b140, 0xc084019750)
  14. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1220 +0x43
  15. net/http.(*ServeMux).ServeHTTP(0xc0840381b0, 0x332940, 0xc08400b140, 0xc084019750)
  16. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1496 +0x166
  17. net/http.serverHandler.ServeHTTP(0xc084005e10, 0x332940, 0xc08400b140, 0xc084019750)
  18. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1597 +0x171
  19. net/http.(*conn).serve(0xc08403f580)
  20. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1167 +0x7ba
  21. created by net/http.(*Server).Serve
  22. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1644 +0x28e

说明:对于已经存在的页面,程序按预期工作,我能够编辑页面并稍后加载它们。

英文:

The following program is a custom version of the webserver from the official tutorial at this page. Only I've modified the save() and loadPage() functions to save my pages to neo4j using jmcvetta's package neoism.

  1. // web1 project main.go
  2. package main
  3. import (
  4. "errors"
  5. "fmt"
  6. "github.com/jmcvetta/neoism"
  7. "html/template"
  8. "io/ioutil"
  9. "net/http"
  10. "regexp"
  11. )
  12. type Page struct {
  13. Title string
  14. Body string
  15. }
  16. func (p *Page) save() error {
  17. db, err := neoism.Connect("http://localhost:7474/db/data")
  18. if err != nil {
  19. return err
  20. }
  21. res := []struct {
  22. N neoism.Node
  23. }{}
  24. cq := neoism.CypherQuery{
  25. Statement: "MERGE (n:Page {title: {title}}) ON MATCH SET n.body = {body} RETURN n",
  26. Parameters: neoism.Props{"title": p.Title, "body": p.Body},
  27. Result: &res,
  28. }
  29. db.Cypher(&cq)
  30. return nil
  31. }
  32. func loadPage(title string) (*Page, error) {
  33. db, err := neoism.Connect("http://localhost:7474/db/data")
  34. if err != nil {
  35. return nil, err
  36. }
  37. res := []struct {
  38. Title string `json:"a.title"` // `json` tag matches column name in query
  39. Body string `json:"a.body"`
  40. }{}
  41. cq := neoism.CypherQuery{
  42. Statement: `
  43. MATCH (a:Page)
  44. WHERE a.title = {name}
  45. RETURN a.title, a.body
  46. `,
  47. Parameters: neoism.Props{"name": title},
  48. Result: &res,
  49. }
  50. db.Cypher(&cq)
  51. r := res[0]
  52. if r.Title == "" || r.Body == "" {
  53. return nil, errors.New("Page doesn't exist")
  54. }
  55. return &Page{Title: r.Title, Body: r.Body}, nil
  56. }
  57. func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
  58. p, err := loadPage(title)
  59. if err != nil {
  60. http.Redirect(w, r, "/edit/"+title, http.StatusFound)
  61. return
  62. }
  63. renderTemplate(w, "view", p)
  64. }
  65. func editHandler(w http.ResponseWriter, r *http.Request, title string) {
  66. p, err := loadPage(title)
  67. if err != nil {
  68. p = &Page{Title: title}
  69. }
  70. renderTemplate(w, "edit", p)
  71. }
  72. func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
  73. body := r.FormValue("body")
  74. p := &Page{Title: title, Body: body}
  75. err := p.save()
  76. if err != nil {
  77. http.Error(w, err.Error(), http.StatusInternalServerError)
  78. return
  79. }
  80. http.Redirect(w, r, "/view/"+title, http.StatusFound)
  81. }
  82. func homeHandler(w http.ResponseWriter, r *http.Request) {
  83. body, err := ioutil.ReadFile("home.html")
  84. if err != nil {
  85. http.Error(w, err.Error(), http.StatusInternalServerError)
  86. return
  87. }
  88. fmt.Fprintf(w, "%s", body)
  89. }
  90. func rootHandler(w http.ResponseWriter, r *http.Request) {
  91. http.Redirect(w, r, "/home", http.StatusFound)
  92. }
  93. var templates = template.Must(template.ParseFiles("edit.html", "view.html"))
  94. func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
  95. err := templates.ExecuteTemplate(w, tmpl+".html", p)
  96. if err != nil {
  97. http.Error(w, err.Error(), http.StatusInternalServerError)
  98. }
  99. }
  100. var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
  101. func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
  102. return func(w http.ResponseWriter, r *http.Request) {
  103. m := validPath.FindStringSubmatch(r.URL.Path)
  104. if m == nil {
  105. http.NotFound(w, r)
  106. return
  107. }
  108. fn(w, r, m[2])
  109. }
  110. }
  111. func main() {
  112. http.HandleFunc("/view/", makeHandler(viewHandler))
  113. http.HandleFunc("/edit/", makeHandler(editHandler))
  114. http.HandleFunc("/save/", makeHandler(saveHandler))
  115. http.HandleFunc("/home", homeHandler)
  116. http.HandleFunc("/", rootHandler)
  117. http.ListenAndServe(":8082", nil)
  118. }

My problem is, i believe, in the the loadPage() function, which doesn't seem to return any error when the page returned has an empty body, causing the handlers to try executing templates with empty structs (at least i tend to think that's what it is).
Does any one see where i did wrong ?

Edit : This is the output when i try to load a page that doesn't already exist :

  1. 2014/06/19 23:13:35 http: panic serving 127.0.0.1:60326: runtime error: index out of range
  2. goroutine 5 [running]:
  3. net/http.func·009()
  4. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1093 +0xb1
  5. runtime.panic(0x6d1f20, 0xa977d7)
  6. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/runtime/panic.c:248 +0x11b
  7. main.loadPage(0xc08407a12a, 0x6, 0x332978, 0xaa7560, 0x3)
  8. C:/Users/Nicolas/Go/src/web1/main.go:55 +0x369
  9. main.editHandler(0x332940, 0xc08400b140, 0xc084019750, 0xc08407a12a, 0x6)
  10. C:/Users/Nicolas/Go/src/web1/main.go:72 +0x34
  11. main.func·001(0x332940, 0xc08400b140, 0xc084019750)
  12. C:/Users/Nicolas/Go/src/web1/main.go:121 +0xc9
  13. net/http.HandlerFunc.ServeHTTP(0xc084024ae0, 0x332940, 0xc08400b140, 0xc084019750)
  14. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1220 +0x43
  15. net/http.(*ServeMux).ServeHTTP(0xc0840381b0, 0x332940, 0xc08400b140, 0xc084019750)
  16. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1496 +0x166
  17. net/http.serverHandler.ServeHTTP(0xc084005e10, 0x332940, 0xc08400b140, 0xc084019750)
  18. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1597 +0x171
  19. net/http.(*conn).serve(0xc08403f580)
  20. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1167 +0x7ba
  21. created by net/http.(*Server).Serve
  22. C:/Users/ADMINI~1/AppData/Local/Temp/2/makerelease250988475/go/src/pkg/net/http/server.go:1644 +0x28e

Precision : for pages that already exist, the program works as intended, I'm able to edit pages and load them later.

答案1

得分: 3

我怀疑在不运行代码的情况下,错误可能出现在这里:

  1. db.Cypher(&cq)
  2. r := res[0]
  3. if r.Title == "" || r.Body == "" {
  4. return nil, errors.New("页面不存在")
  5. }

代码假设存在一个 res[0] 的值。你应该检查一下:

  1. if len(res) == 0 {
  2. return nil, errors.New("页面不存在")
  3. }

你的错误出现在 loadPage 函数中,是一个索引错误。

英文:

Without running the code I suspect the error is here:

  1. db.Cypher(&cq)
  2. r := res[0]
  3. if r.Title == "" || r.Body == "" {
  4. return nil, errors.New("Page doesn't exist")
  5. }

the code assumes that there is a res[0] value. You should check

  1. if len(res) == 0 {
  2. return nil, errors.New("Page does not exists")
  3. }

You error is in your code in loadPage, and is an index error.

huangapple
  • 本文由 发表于 2014年6月20日 04:54:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/24316030.html
匿名

发表评论

匿名网友

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

确定