草庐IT

go - 将 JSON 解码为接口(interface)值

coder 2024-07-06 原文

由于 encoding/json 需要一个非零接口(interface)来解码:我如何可靠地制作用户提供的指针类型的(完整)副本,将其存储在我的 User 接口(interface)中,以及然后 JSON 解码成那个临时的?

注意:这里的目标是“无人值守”——也就是说,从 Redis/BoltDB 中提取字节,解码为接口(interface)类型,然后检查 GetID() 方法接口(interface)定义返回一个非空字符串,带有请求中间件。

Playground :http://play.golang.org/p/rYODiNrfWw

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"

    "time"
)

type session struct {
    ID      string
    User    User
    Expires int64
}

type User interface {
    GetID() string
}

type LocalUser struct {
    ID      string
    Name    string
    Created time.Time
}

func (u *LocalUser) GetID() string {
    return u.ID
}

type Auth struct {
    key []byte
    // We store an instance of userType here so we can unmarshal into it when
    // deserializing from JSON (or other non-gob decoders) into *session.User.
    // Attempting to unmarshal into a nil session.User would otherwise fail.
    // We do this so we can unmarshal from our data-store per-request *without
    // the package user having to do so manually* in the HTTP middleware. We can't
    // rely on the user passing in an fresh instance of their User satisfying type.
    userType User
}

func main() {
    // auth is a pointer to avoid copying the struct per-request: although small
    // here, it contains a 32-byte key, options fields, etc. outside of this example.
    var auth = &Auth{key: []byte("abc")}
    local := &LocalUser{"19313", "Matt", time.Now()}

    b, _, _, err := auth.SetUser(local)
    if err != nil {
        log.Fatalf("SetUser: %v", err)
    }

    user, err := auth.GetUser(b)
    if err != nil {
        log.Fatalf("GetUser: %#v", err)
    }

    fmt.Fprintf(os.Stdout, "%v\n", user)

}

func (auth *Auth) SetUser(user User) (buf []byte, id string, expires int64, err error) {
    sess := newSession(user)

    // Shallow copy the user into our config. struct so we can copy and then unmarshal
    // into it in our middleware without requiring the user to provide it themselves
    // at the start of every request
    auth.userType = user

    b := bytes.NewBuffer(make([]byte, 0))
    err = json.NewEncoder(b).Encode(sess)
    if err != nil {
        return nil, id, expires, err
    }

    return b.Bytes(), sess.ID, sess.Expires, err
}

func (auth *Auth) GetUser(b []byte) (User, error) {
    sess := &session{}

    // Another shallow copy, which means we're re-using the same auth.userType
    // across requests (bad).
    // Also note that we need to copy into it session.User so that encoding/json
    // can unmarshal into its fields.
    sess.User = auth.userType

    err := json.NewDecoder(bytes.NewBuffer(b)).Decode(sess)
    if err != nil {
        return nil, err
    }

    return sess.User, err
}

func (auth *Auth) RequireAuth(h http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
        // e.g. user, err := store.Get(r, auth.store, auth.userType)
        // This would require us to have a fresh instance of userType to unmarshal into
        // on each request.

        // Alternative might be to have:
        // func (auth *Auth) RequireAuth(userType User) func(h http.Handler) http.Handler
        // e.g. called like http.Handle("/monitor", RequireAuth(&LocalUser{})(SomeHandler)
        // ... which is clunky and using closures like that is uncommon/non-obvious.
    }

    return http.HandlerFunc(fn)
}

func newSession(u User) *session {
    return &session{
        ID:      "12345",
        User:    u,
        Expires: time.Now().Unix() + 3600,
    }
}

最佳答案

如果您需要深拷贝一个接口(interface),请将该方法添加到您的接口(interface)中。

type User interface {
  GetID() string
  Copy() User
}

type LocalUser struct {
  ID string
  Name string
  Created time.Time
}

// Copy receives a copy of LocalUser and returns a pointer to it.
func (u LocalUser) Copy() User {
  return &u
}

关于go - 将 JSON 解码为接口(interface)值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35447480/

有关go - 将 JSON 解码为接口(interface)值的更多相关文章

  1. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  2. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

  3. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  4. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  5. ruby-on-rails - Rails 渲染带有驼峰命名法的 json 对象 - 2

    我在一个简单的RailsAPI中有以下Controller代码:classApi::V1::AccountsControllerehead:not_foundendendend问题在于,生成的json具有以下格式:{id:2,name:'Simpleaccount',cash_flows:[{id:1,amount:34.3,description:'simpledescription'},{id:2,amount:1.12,description:'otherdescription'}]}我需要我生成的json是camelCase('cashFlows'而不是'cash_flows'

  6. ruby - 使用 JSON gem 将自定义对象转换为 JSON - 2

    我正在学习如何使用JSONgem解析和生成JSON。我可以轻松地创建数据哈希并将其生成为JSON;但是,在获取一个类的实例(例如Person实例)并将其所有实例变量放入哈希中以转换为JSON时,我脑袋放屁。这是我遇到问题的例子:require"json"classPersondefinitialize(name,age,address)@name=name@age=age@address=addressenddefto_jsonendendp=Person.new('JohnDoe',46,"123ElmStreet")p.to_json我想创建一个.to_json方法,这样我就可以获

  7. ruby-on-rails - 如何使用驼峰键名称从 Rails 返回 JSON - 2

    我正在构建一个带有Rails后端的JS应用程序,为了不混淆snake和camelcases,我想通过从服务器返回camelcase键名来规范化这一切。因此,当从API返回时,user.last_name将返回user.lastName。我如何实现这一点?谢谢!编辑:添加Controller代码classApi::V1::UsersController 最佳答案 我的方法是使用ActiveModelSerializer和json_api适配器:在你的Gemfile中,添加:gem'active_model_serializers'创建

  8. ruby-on-rails - 如何将数组输出为 JSON? - 2

    我有以下内容:@array.inspect["x1","x2","adad"]我希望能够将其格式化为:client.send_message(s,m,{:id=>"x1",:id=>"x2",:id=>"adad"})client.send_message(s,m,???????)如何在????????中获得@array输出?空间作为ID?谢谢 最佳答案 {:id=>"x1",:id=>"x2",:id=>"adad"}不是有效的散列,因为您有键冲突它应该是这样的:{"ids":["x1","x2","x3"]}更新:@a=["x1

  9. ruby - 使用 jbuilder 创建具有动态哈希键的 JSON - 2

    这里我想输出带有动态组名的json而不是单词组@tickets.eachdo|group,v|json.group{json.array!vdo|ticket|json.partial!'tickets/ticket',ticket:ticketend}end@ticket是这样的散列{a:[....],b:[.....]}我想要这样的输出{a:[.....],b:[....]} 最佳答案 感谢@AntarrByrd,这个问题有类似的答案:JBuilderdynamickeysformodelattributes使用上面的逻辑我已经

  10. ruby - 展平嵌套的 json 对象 - 2

    我正在寻找一种将“json”散列展平为展平散列但将路径信息保留在展平键中的方法。例如:h={"a"=>"foo","b"=>[{"c"=>"bar","d"=>["baz"]}]}flatten(h)应该返回:{"a"=>"foo","b_0_c"=>"bar","b_0_d_0"=>"baz"} 最佳答案 这应该可以解决您的问题:h={'a'=>'foo','b'=>[{'c'=>'bar','d'=>['baz']}]}moduleEnumerabledefflatten_with_path(parent_prefix=nil)

随机推荐