#forms #go #interface #go-gin
#формы #Вперед #интерфейс #go-gin
Вопрос:
Я хочу создать функцию для обработки любых форм. Я хочу, чтобы он мог обрабатывать любые типы данных. Я пытаюсь использовать интерфейс для выполнения этой задачи.
type Person struct {
name string
lastName string
}
func HTMLForm(c *gin.Context) {
var f Person
c.ShouldBind(amp;f)
c.JSON(http.StatusOK, f)
}
// with this function i get the correct info
// output: {"name":"john","lastName":"snow"}
func HTMLForm(c *gin.Context) {
var f interface{}
c.ShouldBind(amp;f)
c.JSON(http.StatusOK, f)
}
// when i use the interface to make it usefull for any type of that
// i get null
// output: null
func HTMLForm(c *gin.Context) {
var f interface{}
ShouldBindJSON(f)
c.JSON(http.StatusOK, f)
}
// output: null
Я хочу получить с интерфейсом тот же результат, который я получаю с типом данных «Person».
// Another example of how i am using f
type Login struct {
User string
Password string
}
func main() {
router := gin.Default()
router.POST("/loginForm", func(c *gin.Context) {
var f interface{}
if err := c.ShouldBind(amp;f); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, f)
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
// output: null
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Обновить
Я хочу попытаться лучше объяснить мою проблему. Может быть, это обновление станет более понятным.
// Golang code
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// Binding from JSON
type Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
}
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*")
router.GET("/login", GetLogin)
router.POST("/loginJSON", PostJSONForm)
router.POST("/loginXML", PostXMLForm)
router.POST("/loginForm", PostHTMLForm)
/*
sudo lsof -n -i :8080
kill -9 <PID>
*/
router.Run(":8080")
}
func GetLogin(c *gin.Context) {
c.HTML(http.StatusOK, "login.tmpl", nil)
}
// Example for binding JSON ({"user": "manu", "password": "123"})
// curl -v -X POST http://localhost:8080/loginJSON -H 'content-type: application/json' '{ "user": "manu", "password"="123" }'
func PostJSONForm(c *gin.Context) {
//var json Login
var json interface{}
//var form map[string]interface{}
if err := c.ShouldBindJSON(amp;json); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
/*
if json.User != "manu" || json.Password != "123" {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
*/
c.JSON(http.StatusOK, "json")
c.JSON(http.StatusOK, json)
}
// Example for binding XML (
// <?xml version="1.0" encoding="UTF-8"?>
// <root>
// <user>user</user>
// <password>123</password>
// </root>)
// curl -v -X POST http://localhost:8080/loginXML -H 'content-type: application/json' -d '{ "user": "manu", "password"="123" }'
func PostXMLForm(c *gin.Context) {
//var xml Login
var xml interface{}
//var form map[string]interface{}
if err := c.ShouldBindXML(amp;xml); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
/*
if xml.User != "manu" || xml.Password != "123" {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
*/
c.JSON(http.StatusOK, "xml")
c.JSON(http.StatusOK, xml)
}
// Example for binding a HTML form (user=manuamp;password=123)
// curl -v -X POST http://localhost:8080/loginForm -H 'content-type: application/json' -d '{ "user": "manu", "password":"123" }'
func PostHTMLForm(c *gin.Context) {
//var form Login
var form interface{}
//var form map[string]interface{}
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(amp;form); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
/*
if form.User != "manu" || form.Password != "123" {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
*/
c.JSON(http.StatusOK, "html")
c.JSON(http.StatusOK, form)
}
//Template
<h1>Login</h1>
<form action="/loginForm" method="POST">
<label>user:</label><br>
<input type="text" name="user"><br>
<label>password:</label><br>
<input type="text" name="password"><br>
<input type="submit">
</form>
-
Я пробовал все эти разные варианты. Работает только один, я объясню подробнее ниже.
-
Это работает идеально, если я использую «var form Login» вместо «var from interface{}». Но мне нужно, чтобы она могла работать с любым типом данных, поэтому мне нужно, чтобы она работала с интерфейсом {}.
-
У меня был «успешный» вывод, только с одной из попыток interface {}:
$ curl -X POSThttp://localhost:8080/loginForm -H ‘content-type: application / json’ -d ‘{ «user»: «manu», «password»:»123″ }’
вывод: «html»{«password»: «123»,»user»: «manu»}
- Но когда я использую ее в HTML-форме, в браузере, с тем шаблоном, который я опубликовал, я получаю:
вывод: «html»null
- Я не уверен, что то, что я получаю (пункт 3), действительно является успешным результатом. Когда я использую Login var, он работает нормально, с curl и brower, вывод инвертируется:
$ curl -X POSThttp://localhost:8080/loginForm -H ‘content-type: application / json’ -d ‘{ «user»: «manu», «password»:»123″ }’
вывод: «html»{«user»: «manu»,»password»:»123″}
Это вся информация, которую я смог получить до сих пор.
Комментарии:
1. используйте map[string]interface{} вместо interface{}
Ответ №1:
Эта версия последнего ответа работала с отправкой html-формы и curl json.
package main
import (
"net/http"
"fmt"
"github.com/gin-gonic/gin"
)
// Binding from JSON
type Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
}
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*")
router.GET("/login", func(c *gin.Context) {
c.HTML(http.StatusOK, "login.tmpl", nil)
})
// Example for binding a HTML form (user=manuamp;password=123)
router.POST("/loginForm", func(c *gin.Context) {
var form Login
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(amp;form); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, form)
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
И шаблоны/login.tmpl:
<html>
<body>
<h1>Login</h1>
<form action="/loginForm" method="POST">
<label>user:</label><br>
<input type="text" name="user"><br>
<label>password:</label><br>
<input type="text" name="password"><br>
<input type="submit">
</form>
</body>
</html>
Ответ №2:
Вы пытаетесь использовать ShouldBindJSON? Потому что он должен знать, каким типом вы хотите быть
ShouldBind проверяет тип содержимого, чтобы автоматически выбрать механизм привязки, в зависимости от заголовка «Content-Type» используются разные привязки:
из исходного кода gin:
// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
func (c *Context) ShouldBindJSON(obj interface{}) error {
return c.ShouldBindWith(obj, binding.JSON)
}
Обновить:
В вашем случае это работает для меня?
router := gin.Default()
router.POST("/loginForm", func(c *gin.Context) {
var f interface{}
if err := c.ShouldBindJSON(amp;f); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
log.Print(f)
c.JSON(http.StatusOK, f)
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
Пример входа в систему
curl -X POST -H "Content-Type: application/json"
--data '{"username":"xyz","password":"xyz"}' localhost:8080/loginForm
Результат
[GIN-debug] POST /loginForm --> main.main.func1 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8080
map[password:xyz username:xyz]
[GIN] 2019/04/23 - 10:07:00 | 200 | 239.317µs | ::1 | POST /loginForm
//////////////////////////////////
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
// Binding from JSON
type Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
}
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*")
router.GET("/login", func(c *gin.Context) {
c.HTML(http.StatusOK, "login.tmpl", nil)
})
// Example for binding a HTML form (user=manuamp;password=123)
router.POST("/loginForm", func(c *gin.Context) {
var form interface{}
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(amp;form); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, form)
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
//шаблон
<h1>Login</h1>
<form action="/loginForm" method="POST">
<label>user:</label><br>
<input type="text" name="user"><br>
<label>password:</label><br>
<input type="text" name="password"><br>
<input type="submit">
</form>
// Я получаю null при использовании de HTML from, когда я пытаюсь выполнить команду curl, она работает
Комментарии:
1. Спасибо за комментарий. Я попробовал, и я получаю тот же результат.
2. функция HtmlForm(c * gin.Context) { var f interface { } ShouldBindJSON (f) c.JSON (http. StatusOK, f) } вывод: null
3. В вашем случае вы должны использовать c.ShouldBindJSON (f) ?
4. Я только что добавил еще один пример того, как я пытаюсь его использовать.
5. Я пробовал f и amp; f, но безуспешно.