获取/articles/:article_id在Gin-Gonic/Gin中不起作用。

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

GET /articles/:article_id Not working Gin-Gonic/Gin

问题

我正在处理一个API,GET和POST都正常工作,除了当我尝试通过ID获取一个选择的记录时(例如/articles/2)。文章存在,并且通过/articles路由检索所有记录时,我得到了正确的响应。以下是堆栈跟踪。

$ go run main.go
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env:   export GIN_MODE=release
- using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET   /                         --> main.index (3 handlers)
[GIN-debug] GET   /articles                 --> main.ArticlesList (3 handlers)
[GIN-debug] POST  /articles                 --> main.ArticlePost (3 handlers)
[GIN-debug] GET   /articles/:article_id     --> main.ArticlesDetail (3 handlers)
[GIN-debug] Listening and serving HTTP on :8000
2015/06/18 10:31:49 Panic recovery -> interface conversion: error is *errors.errorString, not *errors.Error
c:/go/src/runtime/panic.go:387 (0x4114b6)
        gopanic: reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
c:/go/src/runtime/iface.go:181 (0x40ae1a)
        assertI2T: panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:37 (0x401261)
        checkErr: log.Fatalln(msg, err.(*errors.Error).ErrorStack())
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:97 (0x401e2c)
        getArticle: checkErr(err, "selectOne failed")
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:60 (0x4016a7)
        ArticlesDetail: article := getArticle(a_id)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
        (*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/logger.go:56 (0x442ff0)
        func.007: c.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
        (*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/recovery.go:43 (0x4437e0)
        func.009: c.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
        (*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/gin.go:249 (0x43b275)
        (*Engine).handleHTTPRequest: context.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/gin.go:230 (0x43aff9)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
c:/go/src/net/http/server.go:1703 (0x4ad385)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
c:/go/src/net/http/server.go:1204 (0x4ab378)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
c:/go/src/runtime/asm_386.s:2287 (0x435c01)
        goexit:

代码如下:

package main

import (
	"github.com/gin-gonic/gin"
	"database/sql"
	"github.com/coopernurse/gorp"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"time"
	"strconv"
	"github.com/go-errors/errors"
)

type Article struct {
	Id int64 `db:"article_id"`
	Created int64
	Title string
	Content string
}

var dbmap = initDb()

func initDb() gorp.DbMap {
	db, err := sql.Open("sqlite3", "db.sqlite3")
	checkErr(err, "sql.Open faild")
	dbmap := gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
	dbmap.AddTableWithName(Article{}, "articles").SetKeys(true, "Id")
	err = dbmap.CreateTablesIfNotExists()
	checkErr(err, "Create tables failed")
	return dbmap
}

func checkErr(err error, msg string) {
	if err != nil {
		log.Fatalln(msg, err.(*errors.Error).ErrorStack())
	}
}

func index (c *gin.Context) {
	content := gin.H{"Hello": "World"}
	c.JSON(200, content)
}

func ArticlesList(c *gin.Context) {
	var articles []Article
	_, err := dbmap.Select(&articles, "select * from articles order by article_id")
	checkErr(err, "Select failed")
	content := gin.H{}
	for k, v := range articles {
		content[strconv.Itoa(k)] =v
	}
	c.JSON(200, content)
}

func ArticlesDetail(c *gin.Context) {
	article_id := c.Params.ByName("id")
	a_id, _ := strconv.Atoi(article_id)
	article := getArticle(a_id)
	content := gin.H{"title": article.Title, "content": article.Content}
	c.JSON(200, content)
}

func ArticlePost(c *gin.Context) {
	var json Article

	c.Bind(&json)
	article := createArticle(json.Title, json.Content)
	if article.Title == json.Title {
		content := gin.H{
			"result": "Success",
			"title": article.Title,
			"content": article.Content,
		}
		c.JSON(201, content)
	} else {
		c.JSON(500, gin.H{"result": "An error occured"})
	}
}

func createArticle(title, body string) Article {
	article := Article{
		Created: time.Now().UnixNano(),
		Title: title,
		Content: body,
	}

	err := dbmap.Insert(&article)
	checkErr(err, "Insert failed")
	return article
}

func getArticle(article_id int) Article {
	article := Article{}
	err := dbmap.SelectOne(&article, "select * from articles where article_id=?", article_id)
	checkErr(err, "selectOne failed")
	return article
}

func main() {
	app := gin.Default()
	app.GET("/", index)
	app.GET("/articles", ArticlesList)
	app.POST("/articles", ArticlePost)
	app.GET("/articles/:article_id", ArticlesDetail)
	app.Run(":8000")
}
英文:

I am working on an API and GET and POST are working fine except when I try and get a select record by its ID (e.g. /articles/2). The article exists and when retrieving all records via the /articles route I get a proper response. Here is the stack trace.

    $ go run main.go
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env:   export GIN_MODE=release
- using code:  gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET   /                         --> main.index (3 handlers)
[GIN-debug] GET   /articles                 --> main.ArticlesList (3 handlers)
[GIN-debug] POST  /articles                 --> main.ArticlePost (3 handlers)
[GIN-debug] GET   /articles/:article_id     --> main.ArticlesDetail (3 handlers)
[GIN-debug] Listening and serving HTTP on :8000
2015/06/18 10:31:49 Panic recovery -> interface conversion: error is *errors.errorString, not *errors.Error
c:/go/src/runtime/panic.go:387 (0x4114b6)
gopanic: reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
c:/go/src/runtime/iface.go:181 (0x40ae1a)
assertI2T: panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:37 (0x401261)
checkErr: log.Fatalln(msg, err.(*errors.Error).ErrorStack())
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:97 (0x401e2c)
getArticle: checkErr(err, "selectOne failed")
c:/Users/Fresh/go/src/github.com/jisaw/portfolio-server/main.go:60 (0x4016a7)
ArticlesDetail: article := getArticle(a_id)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
(*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/logger.go:56 (0x442ff0)
func.007: c.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
(*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/recovery.go:43 (0x4437e0)
func.009: c.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/context.go:86 (0x43694a)
(*Context).Next: c.handlers[c.index](c)
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/gin.go:249 (0x43b275)
(*Engine).handleHTTPRequest: context.Next()
c:/Users/Fresh/go/src/github.com/gin-gonic/gin/gin.go:230 (0x43aff9)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
c:/go/src/net/http/server.go:1703 (0x4ad385)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
c:/go/src/net/http/server.go:1204 (0x4ab378)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
c:/go/src/runtime/asm_386.s:2287 (0x435c01)
goexit:

And the Code

package main
import (
"github.com/gin-gonic/gin"
"database/sql"
"github.com/coopernurse/gorp"
_ "github.com/mattn/go-sqlite3"
"log"
"time"
"strconv"
"github.com/go-errors/errors"
)
type Article struct {
Id int64 `db:"article_id"`
Created int64
Title string
Content string
}
var dbmap = initDb()
func initDb() gorp.DbMap {
db, err := sql.Open("sqlite3", "db.sqlite3")
checkErr(err, "sql.Open faild")
dbmap := gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
dbmap.AddTableWithName(Article{}, "articles").SetKeys(true, "Id")
err = dbmap.CreateTablesIfNotExists()
checkErr(err, "Create tables failed")
return dbmap
}
func checkErr(err error, msg string) {
if err != nil {
log.Fatalln(msg, err.(*errors.Error).ErrorStack())
}
}
func index (c *gin.Context) {
content := gin.H{"Hello": "World"}
c.JSON(200, content)
}
func ArticlesList(c *gin.Context) {
var articles []Article
_, err := dbmap.Select(&articles, "select * from articles order by article_id")
checkErr(err, "Select failed")
content := gin.H{}
for k, v := range articles {
content[strconv.Itoa(k)] =v
}
c.JSON(200, content)
}
func ArticlesDetail(c *gin.Context) {
article_id := c.Params.ByName("id")
a_id, _ := strconv.Atoi(article_id)
article := getArticle(a_id)
content := gin.H{"title": article.Title, "content": article.Content}
c.JSON(200, content)
}
func ArticlePost(c *gin.Context) {
var json Article
c.Bind(&json)
article := createArticle(json.Title, json.Content)
if article.Title == json.Title {
content := gin.H{
"result": "Success",
"title": article.Title,
"content": article.Content,
}
c.JSON(201, content)
} else {
c.JSON(500, gin.H{"result": "An error occured"})
}
}
func createArticle(title, body string) Article {
article := Article{
Created: time.Now().UnixNano(),
Title: title,
Content: body,
}
err := dbmap.Insert(&article)
checkErr(err, "Insert failed")
return article
}
func getArticle(article_id int) Article {
article := Article{}
err := dbmap.SelectOne(&article, "select * from articles where article_id=?", article_id)
checkErr(err, "selectOne failed")
return article
}
func main() {
app := gin.Default()
app.GET("/", index)
app.GET("/articles", ArticlesList)
app.POST("/articles", ArticlePost)
app.GET("/articles/:article_id", ArticlesDetail)
app.Run(":8000")
}

答案1

得分: 2

堆栈跟踪很明确:interface conversion: error is *errors.errorString, not *errors.Error

因此,在checkErr()函数中,对err进行的类型断言是错误的。

以下是解决方案:

func checkErr(err error, msg string) {
    if err != nil {
        log.Fatalln(msg, err.(*errors.errorString).ErrorStack())
    }
}

如果你想了解为什么会出现这个panic,我建议你阅读Golang关于类型断言的规范

英文:

The stacktrace is explicit: interface conversion: error is *errors.errorString, not *errors.Error.

So in checkErr(), the type assertion on err is wrong.

Here is the solution:

func checkErr(err error, msg string) {
if err != nil {
log.Fatalln(msg, err.(*errors.errorString).ErrorStack())
}
}

If you need to understand why you are getting this panic, I'd suggest you to read the Golang specs about type assertions.

huangapple
  • 本文由 发表于 2015年6月18日 23:43:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/30919986.html
匿名

发表评论

匿名网友

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

确定