英文:
GoLang Get Method Returns Missing Info
问题
我正在尝试使用golang、gin和gorm框架获取一些个人资料信息。这是我的数据结构:
type Model struct {
Skills []string
Languages []string
}
这是我的方法:
var skillname []string
var languagename []string
var langs []Models.Language
var skills []Models.Skill
session, _ := store.Get(c.Request, "sessioncontrol")
i := session.Values["sessionid"]
skillcount := int(Config.DB.Find(&skills, "user_id = ?", i).RowsAffected)
langcount := int(Config.DB.Find(&langs, "user_id = ?", i).RowsAffected)
fmt.Println(langcount)
fmt.Println(skillcount)
for _, lang := range langs {
var langc Models.LanguageCatalog
fmt.Printf("lang:")
fmt.Println(langcount)
Config.DB.First(&langc, "id = ?", lang.LanguageCatalogID)
fmt.Printf("catalogname:")
fmt.Println(langc.Name)
languagename = append(languagename, langc.Name)
}
for _, skill := range skills {
var skillc Models.SkillCatalog
fmt.Printf("skill:")
fmt.Println(skillcount)
Config.DB.First(&skillc, "id = ?", skill.SkillCatalogID)
fmt.Printf("catalognames:")
fmt.Println(skillc.Name)
skillname = append(skillname, skillc.Name)
}
for _, snm := range skillname {
fmt.Println(snm)
}
for _, lnm := range languagename {
fmt.Println(lnm)
}
model.Skills = skillname
model.Languages = languagename
for _, skname := range model.Skills {
fmt.Println(skname)
}
for _, lname := range model.Languages {
fmt.Println(lname)
}
err := c.ShouldBindJSON(&model)
c.JSON(200, model)
fmt.Print(err)
return
我使用fmt方法来检查数据是否实际接收到了,而且确实接收到了。这是我的终端输出:
2
4
lang:2
catalogname:Spanish
lang:2
catalogname:German
skill:4
catalognames:Java
skill:4
catalognames:.net
skill:4
catalognames:JQuery
skill:4
catalognames:Go
Java
.net
JQuery
Go
Spanish
German
Java
.net
JQuery
Go
Spanish
German
json: cannot unmarshal object into Go struct field Model.Languages of type string
我确实有4个技能记录和2个语言方法,就像在终端和数据库中打印的那样。然而,当我使用Postman调用GET方法时,我得到的结果是:
{
"Languages": [
"Spanish"
],
"Skills": [
"Java",
".net"
]
}
由于我得到了"cannot unmarshal"错误,我尝试使用模型数组而不是字符串数组,但结果仍然相同,没有错误消息。为了通过GET调用获取完整数据,我应该怎么做?谢谢你的时间。
英文:
I am trying to get some profile info using golang, gin and gorm frame works. Here is my data struct.
type Model struct {
Skills []string
Languages []string
}
And my method;
var skillname []string
var languagename []string
var langs []Models.Language
var skills []Models.Skill
session, _ := store.Get(c.Request, "sessioncontrol")
i := session.Values["sessionid"]
skillcount := int(Config.DB.Find(&skills, "user_id = ?", i).RowsAffected)
langcount := int(Config.DB.Find(&langs, "user_id = ?", i).RowsAffected)
fmt.Println(langcount)
fmt.Println(skillcount)
for _, lang := range langs {
var langc Models.LanguageCatalog
fmt.Printf("lang:")
fmt.Println(langcount)
Config.DB.First(&langc, "id = ?", lang.LanguageCatalogID)
fmt.Printf("catalogname:")
fmt.Println(langc.Name)
languagename = append(languagename, langc.Name)
}
for _, skill := range skills {
var skillc Models.SkillCatalog
fmt.Printf("skill:")
fmt.Println(skillcount)
Config.DB.First(&skillc, "id = ?", skill.SkillCatalogID)
fmt.Printf("catalognames:")
fmt.Println(skillc.Name)
skillname = append(skillname, skillc.Name)
}
for _, snm := range skillname {
fmt.Println(snm)
}
for _, lnm := range languagename {
fmt.Println(lnm)
}
model.Skills = skillname
model.Languages = languagename
for _, skname := range model.Skills {
fmt.Println(skname)
}
for _, lname := range model.Languages {
fmt.Println(lname)
}
err := c.ShouldBindJSON(&model)
c.JSON(200, model)
fmt.Print(err)
return
I used fmt methods to check whether data is actually receiving or not. And it is. Here is my terminal output;
2
4
lang:2
catalogname:Spanish
lang:2
catalogname:German
skill:4
catalognames:Java
skill:4
catalognames:.net
skill:4
catalognames:JQuery
skill:4
catalognames:Go
Java
.net
JQuery
Go
Spanish
German
Java
.net
JQuery
Go
Spanish
German
json: cannot unmarshal object into Go struct field Model.Languages of type string
I really have 4 skills record and 2 language method like printed in the terminal at the database. However when I call GET method using postman what I got is;
{
"Languages": [
"Spanish"
],
"Skills": [
"Java",
".net"
]
}
Since I got "cannot unmarshal" error, I tried same by using model arrays instead of string arrays but the result was same without the error message. What should I do in order to get full data by GET call. Thanks for your time.
答案1
得分: 1
我猜测你从Postman传入的请求包括一个请求体(例如 {"Skills":["Java",".net"],"Languages":["Spanish"]}
)。在这种情况下,我们可以使用以下代码复制该问题:
package main
import (
"bytes"
"fmt"
"io"
"net/http/httptest"
"github.com/gin-gonic/gin"
)
type Model struct {
Skills []string
Languages []string
}
func main() {
// 模拟一个HTTP请求(使我们能够提供一个最小化、可重现的示例)
requestTxt := bytes.NewBuffer([]byte(`{"Skills":["Java",".net"],"Languages":["Spanish"]}`))
req := httptest.NewRequest("GET", "/", requestTxt)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = req
// 填充切片(数据库查询与问题无关-你已经证明它们有效)
skills := []string{"Java", ".net", "JQuery"}
langs := []string{"Spanish", "German"}
model := Model{
Skills: skills,
Languages: langs,
}
// 根据你的问题编写代码
err := c.ShouldBindJSON(&model)
fmt.Println("ShouldBindJSON Error", err)
c.JSON(200, model)
// 输出将发送回Postman的响应
body, _ := io.ReadAll(w.Result().Body)
fmt.Println("response: ", string(body))
}
运行这段代码会得到你所说的结果:
{"Skills":["Java",".net"],"Languages":["Spanish"]}
之所以会出现这种情况,是因为context.ShouldBindJSON
将请求解析为你传入的变量;它用于当你期望请求包含JSON并希望将其解组为Go的struct
时。因此,你首先将数据放入model
,然后通过调用ShouldBindJSON
来覆盖它。
要修复这个问题,删除err := c.ShouldBindJSON(&model)
这一行(以及打印错误的那一行),结果将如预期:
{"Skills":["Java",".net","JQuery"],"Languages":["Spanish","German"]}
注意:正如我在开始时所说,这是基于一些猜测。如果这没有帮助,请修改我提供的代码,使其与你的情况相匹配(如果你提供一个最小化、可重现的示例,那么理解和回答你的问题会更简单)。
英文:
I'm going to guess that the request you are passing in from postman includes a request body (e.g. {"Skills":["Java",".net"],"Languages":["Spanish"]}
). That being the case we can duplicate the issue with:
package main
import (
"bytes"
"fmt"
"io"
"net/http/httptest"
"github.com/gin-gonic/gin"
)
type Model struct {
Skills []string
Languages []string
}
func main() {
// Simulate an HTTP request (enables us to provide a Minimal, Reproducible Example)
requestTxt := bytes.NewBuffer([]byte(`{"Skills":["Java",".net"],"Languages":["Spanish"]}`))
req := httptest.NewRequest("GET", "/", requestTxt)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = req
// Populate the slices (the database queries are irrelevant - you have shown that they work)
skills := []string{"Java", ".net", "JQuery"}
langs := []string{"Spanish", "German"}
model := Model{
Skills: skills,
Languages: langs,
}
// Code as per your question
err := c.ShouldBindJSON(&model)
fmt.Println("ShouldBindJSON Error", err)
c.JSON(200, model)
// Output the response that would be sent back to postman
body, _ := io.ReadAll(w.Result().Body)
fmt.Println("response: ", string(body))
}
Running this gives me the result you say you are getting:
{"Skills":["Java",".net"],"Languages":["Spanish"]}
The reason that this is happening is that context.ShouldBindJSON
process the request INTO the variable you pass; it is used when you expect the request to contain JSON and want to unmarshal that into a Go struct
. So you are putting data into model
and then overwriting it with the call to ShouldBindJSON
.
To fix this remove the line err := c.ShouldBindJSON(&model)
(and the line printing the error) and the result will be as expected:
{"Skills":["Java",".net","JQuery"],"Languages":["Spanish","German"]}
Note: As I said at the start this is based on some guesswork. If this does not help please modify the code I have provided so that it matches your situation (if you provide a minimal, reproducible example then it's a lot simpler to understand/answer your question).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论