如何在golang中将请求一般化为JSON

如何在golang中将请求一般化为JSON,json,http,generics,go,types,Json,Http,Generics,Go,Types,我试图将一个类型和一个请求传递到一个函数中,然后在该函数中将请求解组为一个变量并返回它 我认为我的方法是错误的,因为当我尝试这样做时: package controllers import ( "encoding/json" "errors" "io" "io/ioutil" "reflect" ) func GetTypeFromReq(c *App, ty interface{}) (interface{}, error) { //get

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

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

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
}
我得到错误“接口转换:接口{}是reflect.Value,不是models.User”


有关如何实现此目的的任何提示?

修改最后一行的代码:将
用户:=inter.(models.user)
更改为
用户:=inter.Interface()(models.user)
,请尝试

接口转换:接口{}是reflect.Value,不是models.User

关于消息错误,我非常直截了当。您的
项目
反映.值
它不是
模型.用户

因此,我认为在您的代码中,您可以将
更改为models.User

但是我假设您正在创建一个可以处理所有类型模型的函数,在本例中是
models.User{}

您的方法成本很高,因为它使用的是
接口
。您可以像这样直接转换
传入请求

inter, err := GetTypeFromReq(&c, models.User{})
if err != nil {
    revel.ERROR.Println(err.Error())
}
user := inter.(models.User)
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
}
如果您的
主体
与您的模型具有相同的结构,它将为您提供值,如果没有,则为
错误

请注意,使用
界面时需要小心。你可以从中看到一些指导原则。使用接口:

  • 当API的用户需要提供实现细节时
  • 当API有多个实现时,它们需要在内部维护
  • 当API中可以更改的部分已经确定并且需要解耦时

您的函数将
型号的值转换为
界面
,然后返回
界面
值。这就是它昂贵的原因。

以下是如何修改函数以使其按预期工作:

func GetTypeFromReq(c *App, ty models.User) (models.User, error) {
    //get the type we are going to marshall into
    var item models.User

    //define and set the error that we will be returning to nil
    var retErr error // this var if the value not define then it is nil. Because error is interface

    //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
}
注意调用以获取
reflect.Value
的当前值

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

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
}
像这样使用它:

inter, err := GetTypeFromReq(&c, models.User{})
if err != nil {
    revel.ERROR.Println(err.Error())
}
user := inter.(models.User)
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
}
使用a简化代码:

var user models.User
err := GetFromReq(&c, &user)
if err != nil {
   revel.ERROR.Println(err.Error())
}
如果
c.Request
*http.Request
c.Response
http.ResponseWriter
,则将函数编写为:

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

无需关闭net/http服务器中的请求主体。使用而不是io.LimitReader来防止客户端意外或恶意发送大型请求并浪费服务器资源。

完成,woops。我想是的。