英文:
Auto parse parameter JSON in Revel (Golang)
问题
Revel在内容类型为"application/json"时无法解析JSON参数。
如何强制执行此操作?
示例:
在POST调用Foundations.Create
函数中,使用http://localhost:9000/foundations
。
在该函数中,我使用fmt.Println("Params :", c.Params)
来检查参数。
Ruby POST JSON数据
#!/usr/bin/env ruby
require "rubygems"
require "json"
require "net/https"
uri = URI.parse("http://localhost:9000/foundations")
http = Net::HTTP.new(uri.host, uri.port)
header = { "Content-Type" => "application/json" }
req = Net::HTTP::Post.new(uri.path, header)
req.body = {
"data" => "mysurface"
}.to_json()
res = http.start { |http| http.request(req) }
调试打印结果为
Params : &{map[] map[] map[] map[] map[] map[] []}
当我不使用"application/json"时,例如:
curl -F 'data=mysurface' http://127.0.0.1:9000/foundations
打印结果为:
Params : &{map[data:[mysurface]] map[] map[] map[] map[data:[mysurface]] map[] []}
英文:
Revel doesn't parse JSON parameter when the content type is "application/json".
How to enforce this ?
Example :
http://localhost:9000/foundations
in POST call Foundations.Create
function.
Into this function I use fmt.Println("Params :", c.Params)
to check parameters
Ruby POST JSON data
#!/usr/bin/env ruby
require "rubygems"
require "json"
require "net/https"
uri = URI.parse("http://localhost:9000/foundations")
http = Net::HTTP.new(uri.host, uri.port)
header = { "Content-Type" => "application/json" }
req = Net::HTTP::Post.new(uri.path, header)
req.body = {
"data" => "mysurface"
}.to_json()
res = http.start { |http| http.request(req) }
The debug print is
Params : &{map[] map[] map[] map[] map[] map[] []}
And when I use none "application/json" like :
curl -F 'data=mysurface' http://127.0.0.1:9000/foundations
The print is :
Params : &{map[data:[mysurface]] map[] map[] map[] map[data:[mysurface]] map[] []}
答案1
得分: 2
问题是,使用json时,Revel无法以与“正常”POST请求相同的方式处理它。通常情况下,它可以将每个参数绑定到一个map[string]string
对象中。但是对于JSON,它必须能够处理数组和嵌套对象,而在不事先知道JSON结构的情况下,没有很好的方法来做到这一点。
因此,解决方案是自己处理它-您应该知道要期望哪些字段,因此创建一个具有这些字段的struct
,并将其解组为json.Unmarshal
。
import (
"encoding/json"
"fmt"
)
type Surface struct {
Data string `json:"data"` //由于我们必须导出字段
//但希望使用小写字母
}
func (c MyController) Action() revel.Result {
var s Surface
err := json.Unmarshal([]byte(c.Request.Body), &s)
fmt.Println(s.Data) //mysurface
}
如果您不喜欢使用json:"data"
标签或不想导出字段,您还可以编写自己的UnmarshalJSON
函数。
type Surface struct {
data string `json:"data"` //可以使用未导出的字段
//因为我们自己处理JSON
}
func (s *Structure) UnmarshalJSON(data []byte) error {
if s == nil {
return errors.New("Structure: UnmarshalJSON on nil pointer")
}
var fields map[string]string
json.Unmarshal(data, &fields)
s.data = fields["data"]
return nil
}
英文:
The issue is that with json, there is no way for Revel to really handle it in the same way it does with a "normal" post request. Normally, it can just bind each param into an map[string]string
object. But with JSON, it has to be able to handle arrays and nested objects, and there is no good way of doing that without knowing beforehand what the structure of the JSON will be.
So the solution, is to handle it yourself - you should know what fields to expect, so create a struct
with those fields, and json.Unmarshal
into it.
import (
"encoding/json"
"fmt"
)
type Surface struct {
Data string `json:"data"` //since we have to export the field
//but want the lowercase letter
}
func (c MyController) Action() revel.Result {
var s Surface
err := json.Unmarshal([]byte(c.Request.Body), &s)
fmt.Println(s.Data) //mysurface
}
If you don't like using the json:"data"
tag or don't want to export your field, you could also write your own UnmarshalJSON
function
type Surface struct {
data string `json:"data"` //can use unexported field
//since we handle JSON ourselves
}
func (s *Structure) UnmarshalJSON(data []byte) error {
if (s == nil) {
return errors.New("Structure: UnmarshalJSON on nil pointer")
}
var fields map[string]string
json.Unmarshal(data, &fields)
*s.data = fields["data"]
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论