json - 如何将 JSON 解码为通过反射创建的值?

标签 json go reflection

package controllers

import (
    "encoding/json"
    "errors"
    "io"
    "io/ioutil"
    "reflect"
)

func GetTypeFromReq(c *App, ty interface{}) (interface{}, error) {
    //get the type we are going to marshall into
    item := reflect.ValueOf(ty)

    //define and set the error that we will be returning to null
    var retErr error
    retErr = nil

    //extract the body from the request and defer closing of the body
    body, err := ioutil.ReadAll(io.LimitReader(c.Request.Body, 1048576))
    defer c.Request.Body.Close()

    //handle errors and unmarshal our data
    if err != nil {
        retErr = errors.New("Failed to Read body: " + err.Error())
    } else if err = json.Unmarshal(body, &item); err != nil {
        retErr = errors.New("Unmarshal Failed: " + err.Error())
    }

    return item, retErr
}

我试图将一个类型和一个请求传递到一个函数中,然后在该函数中将请求解编码到一个变量中并将其返回。

我认为我的方法是错误的,因为当我尝试这样做时:

inter, err := GetTypeFromReq(&c, models.User{})
if err != nil {
    revel.ERROR.Println(err.Error())
}
user := inter.(models.User)

我收到错误“接口(interface)转换:接口(interface) {} 是 reflect.Value,不是 models.User”

关于如何解决这个问题的任何提示?

最佳答案

以下是修改函数以使其按预期工作的方法:

func GetTypeFromReq(c *App, ty interface{}) (interface{}, error) {
  // Allocate new value with same type as ty
  v := reflect.New(reflect.TypeOf(ty))

  //define and set the error that we will be returning to null
  var retErr error
  retErr = nil

  //extract the body from the request and defer closing of the body
  body, err := ioutil.ReadAll(io.LimitReader(c.Request.Body, 1048576))
  defer c.Request.Body.Close()

  //handle errors and unmarshal our data
  if err != nil {
    retErr = errors.New("Failed to Read body: " + err.Error())
  } else if err = json.Unmarshal(body, v.Interface()); err != nil {
    retErr = errors.New("Unmarshal Failed: " + err.Error())
  }

  // v holds a pointer, call Elem() to get the value.
  return v.Elem().Interface(), retErr
}

注意对 Interface() 的调用获取 reflect.Value 的当前值。

这是一种避免反射和类型断言的方法:

func GetFromReq(c *App, item interface{}) error {
  //extract the body from the request and defer closing of the body
  body, err := ioutil.ReadAll(io.LimitReader(c.Request.Body, 1048576))
  defer c.Request.Body.Close()

  //handle errors and unmarshal our data
  if err != nil {
    retErr = errors.New("Failed to Read body: " + err.Error())
  } else if err = json.Unmarshal(body, item); err != nil {
    retErr = errors.New("Unmarshal Failed: " + err.Error())
  }
  return retErr
}

像这样使用它:

var user models.User
err := GetFromReq(&c, &user)
if err != nil {
   revel.ERROR.Println(err.Error())
}

使用 JSON decoder简化代码:

func GetFromReq(c *App, item interface{}) error {
  defer c.Request.Body.Close()
  return json.NewDecoder(io.LimitReader(c.Request.Body, 1048576)).Deocode(item)
}

如果 c.Request 是一个 *http.Request 并且 c.Response 是一个 http.ResponseWriter ,然后将函数写成:

func GetFromReq(c *App, item interface{}) error {
  return json.NewDecoder(http.MaxBytesReaer(c.Response, c.Request.Body, 1048576)).Deocode(item)
}

net/http 服务器中的请求体无需关闭。使用 MaxBytesReader代替 io.LimitReader 以防止客户端意外或恶意发送大请求并浪费服务器资源。

关于json - 如何将 JSON 解码为通过反射创建的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43290970/

相关文章:

csv - 如何使用Go按字母顺序排列csv文件?

go - 从Go结构中提取标签作为reflect.Value

javascript - 根据单击的标题在 Angular4 中排序

c# - 将数组添加到对象列表

go - 如何在 Goji (Golang) 中使用不同的中间件创建单独的路由组?

go - 在Goroutine : why should this work?中推迟对sync.WaitGroup.Wait()的调用

ruby - 有没有一种优雅的方法来测试一个实例方法是否是另一个实例方法的别名?

android - 由意外的 DEX 解析的类;

javascript - 如何设置安全规则以防止删除 firebase 中的数据?

javascript - 如何在 Controller 中格式化 JSON 数据