在Revel(Golang)中自动解析参数JSON

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

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
}

huangapple
  • 本文由 发表于 2014年10月29日 12:29:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/26622804.html
匿名

发表评论

匿名网友

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

确定