【问题标题】:JSON-RPC, "cannot unmarshal object"JSON-RPC,“无法解组对象”
【发布时间】:2017-07-03 18:50:26
【问题描述】:

我正在尝试了解 JSON-RPC 的工作原理,并正在使用 Go 语言 (golang) 对其进行测试。 Go 程序运行良好。它做它应该做的事情。但是当我尝试通过 telnet 发出原始请求时,它会报错。

这里描述了工作且超级简单的 JSON-RPC 服务器:

    // rpc_json_server.go

    package main

    import (
        "log"
        "net"
        "net/http"
        "net/rpc"
        "net/rpc/jsonrpc"
    )

    //------------------------------------------------------------------------------
    // Types
    //------------------------------------------------------------------------------

    type Arithmetic int // Used as RPC Service called 'Arithmetic'

    type Arguments struct {
        A int
        B int
    }

    type Result int

    //------------------------------------------------------------------------------
    // Methods
    //------------------------------------------------------------------------------

    func (t *Arithmetic) Multiply(args *Arguments, res *Result) error {

        *res = Result(args.A * args.B)

        return nil
    }

    //------------------------------------------------------------------------------

    func main() {

        var srv *rpc.Server
        var err error
        var arith *Arithmetic
        var listener net.Listener
        var codec rpc.ServerCodec
        var srv_conntype, srv_host, srv_port, srv_addr, srv_path string
        var srv_debugPath string
        var connection net.Conn

        srv_conntype = "tcp"
        srv_host = "0.0.0.0"
        srv_port = "3000"
        srv_addr = srv_host + ":" + srv_port
        srv_path = "/"
        srv_debugPath = "/debug"

        // Create Server, register Service
        srv = rpc.NewServer()
        arith = new(Arithmetic)
        err = srv.Register(arith)
        if err != nil {
            log.Fatalf("Error. Service Format is not correct. %s\r\n", err) //dbg
        }

        // Handle, listen
        srv.HandleHTTP(srv_path, srv_debugPath)
        listener, err = net.Listen(srv_conntype, srv_addr)
        if err != nil {
            log.Fatalf("Error. Can not listen on %s. %s\r\n", srv_addr, err) //dbg
        }
        log.Printf("Started RPC Handler at %s.\r\n", srv_addr) //dbg

        // Serve
        for {

            connection, err = listener.Accept()
            if err != nil {
                log.Fatal(err)
            }

            codec = jsonrpc.NewServerCodec(connection)

            go srv.ServeCodec(codec)
        }

        err = http.Serve(listener, nil)
        if err != nil {
            log.Fatalf("Serve Error. %s\r\n", err) //dbg
        }
    }

    //------------------------------------------------------------------------------

工作且超级简单的 JSON-RPC 客户端代码如下:

    // rpc_json_client.go

    package main

    import (
        "fmt"
        "log"
        "net"
        "net/rpc"
        "net/rpc/jsonrpc"
    )

    //------------------------------------------------------------------------------
    // Types
    //------------------------------------------------------------------------------

    type Arithmetic int // Used as RPC Service called 'Arithmetic'

    type Arguments struct {
        A int
        B int
    }

    type Result int

    //------------------------------------------------------------------------------
    // Methods
    //------------------------------------------------------------------------------

    func main() {

        var err error
        var srv_conntype, srv_host, srv_port, srv_addr string
        //var srv_path string
        var client *rpc.Client
        var args Arguments
        var result Result
        var serviceName, methodName, funcName string
        var connection net.Conn

        srv_conntype = "tcp"
        srv_host = "0.0.0.0"
        srv_port = "3000"
        srv_addr = srv_host + ":" + srv_port
        //srv_path = "/"

        // Connect to RPC Server
        connection, err = net.Dial(srv_conntype, srv_addr)
        if err != nil {
            log.Fatalf("Error. Can not connect to %s. %s\r\n", srv_addr, err) //dbg
        }
        defer connection.Close()

        // Client
        client = jsonrpc.NewClient(connection)

        // Prepare Call
        serviceName = "Arithmetic"
        methodName = "Multiply"
        funcName = serviceName + "." + methodName
        args.A = 7
        args.B = 8

        // Call remote Procedure
        err = client.Call(funcName, args, &result)
        if err != nil {
            log.Fatalf("Error. %s\r\n", err) //dbg
        }

        // Show Results
        fmt.Printf("[%d; %d] -> [%d].\r\n", args.A, args.B, result) //dbg
    }

再一次。这个 golang 程序运行良好。

但接下来我无法理解。

    telnet localhost 3000
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    {
    "jsonrpc":"2.0", 
    "method":"Arithmetic.Multiply", 
    "params": { "A": 5, "B": 6 },
    "id":1
    }
    {"id":1,"result":null,"error":"json: cannot unmarshal object into Go value of type [1]interface {}"}

请给我一些建议或出现此类错误的原因。原始请求有什么问题?

提前致谢!

【问题讨论】:

  • net/rpc/jsonrpc 的当前实现采用 1 个参数作为 struct 参数。 github.com/golang/go/blob/… 如果要传递命名参数,请作为结构切片传递。

标签: json go marshalling rpc json-rpc


【解决方案1】:

您的代码看起来不错。

但在请求中,params 应该是一个包含实际参数的数组。

尝试使用以下有效负载,它应该可以工作:

{ 
  "jsonrpc":"2.0",
  "method":"Arithmetic.Multiply", 
  "params": [ { "A": 5, "B": 6 } ], 
  "id":1 
} 

(注意包含实际参数的“[”和“]”)

【讨论】:

    猜你喜欢
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-23
    • 2015-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多