JSON-RPC,”cannot unmarshal object”(无法解组对象)

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

JSON-RPC, "cannot unmarshal object"

问题

我正在尝试学习JSON-RPC的工作原理,并在Go语言(golang)中进行测试。Go程序运行正常,它能够按照预期工作。但是,当我尝试通过telnet进行原始请求时,出现了错误。

下面是一个工作正常且非常简单的JSON-RPC服务器的代码:

// rpc_json_server.go

package main

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

//------------------------------------------------------------------------------
// 类型定义
//------------------------------------------------------------------------------

type Arithmetic int // 作为名为'Arithmetic'的RPC服务

type Arguments struct {
    A int
    B int
}

type Result int

//------------------------------------------------------------------------------
// 方法定义
//------------------------------------------------------------------------------

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"

    // 创建Server,注册Service
    srv = rpc.NewServer()
    arith = new(Arithmetic)
    err = srv.Register(arith)
    if err != nil {
        log.Fatalf("错误。Service格式不正确。%s\r\n", err) //dbg
    }

    // 处理请求,监听端口
    srv.HandleHTTP(srv_path, srv_debugPath)
    listener, err = net.Listen(srv_conntype, srv_addr)
    if err != nil {
        log.Fatalf("错误。无法监听%s。%s\r\n", srv_addr, err) //dbg
    }
    log.Printf("已启动RPC处理程序,监听地址:%s。\r\n", srv_addr) //dbg

    // 处理请求
    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错误。%s\r\n", err) //dbg
    }
}

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

这是一个工作正常且非常简单的JSON-RPC客户端的代码

```go
// rpc_json_client.go

package main

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

//------------------------------------------------------------------------------
// 类型定义
//------------------------------------------------------------------------------

type Arithmetic int // 作为名为'Arithmetic'的RPC服务

type Arguments struct {
    A int
    B int
}

type Result int

//------------------------------------------------------------------------------
// 方法定义
//------------------------------------------------------------------------------

func main() {
    var err error
    var srv_conntype, srv_host, srv_port, srv_addr 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

    // 连接RPC服务器
    connection, err = net.Dial(srv_conntype, srv_addr)
    if err != nil {
        log.Fatalf("错误。无法连接到%s。%s\r\n", srv_addr, err) //dbg
    }
    defer connection.Close()

    // 客户端
    client = jsonrpc.NewClient(connection)

    // 准备调用
    serviceName = "Arithmetic"
    methodName = "Multiply"
    funcName = serviceName + "." + methodName
    args.A = 7
    args.B = 8

    // 调用远程过程
    err = client.Call(funcName, args, &result)
    if err != nil {
        log.Fatalf("错误。%s\r\n", err) //dbg
    }

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

再次强调,这个Go语言程序运行正常。

但是,下面的问题我无法理解。

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 {}"}

请给我一些建议或解释这个错误的原因。原始请求中有什么问题?

提前感谢!

<details>
<summary>英文:</summary>

I am trying to learn how JSON-RPC works and am testing it in Go language (golang). The Go program works fine. It does what it should do. But when I try to make a raw request via telnet, it gives an error.

The working and super simple JSON-RPC server is described here:

        // rpc_json_server.go

        package main

        import (
            &quot;log&quot;
            &quot;net&quot;
            &quot;net/http&quot;
            &quot;net/rpc&quot;
            &quot;net/rpc/jsonrpc&quot;
        )

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

        type Arithmetic int // Used as RPC Service called &#39;Arithmetic&#39;

        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 = &quot;tcp&quot;
            srv_host = &quot;0.0.0.0&quot;
            srv_port = &quot;3000&quot;
            srv_addr = srv_host + &quot;:&quot; + srv_port
            srv_path = &quot;/&quot;
            srv_debugPath = &quot;/debug&quot;

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

            // Handle, listen
            srv.HandleHTTP(srv_path, srv_debugPath)
            listener, err = net.Listen(srv_conntype, srv_addr)
            if err != nil {
                log.Fatalf(&quot;Error. Can not listen on %s. %s\r\n&quot;, srv_addr, err) //dbg
            }
            log.Printf(&quot;Started RPC Handler at %s.\r\n&quot;, 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(&quot;Serve Error. %s\r\n&quot;, err) //dbg
            }
        }

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

The working and super simple JSON-RPC client&#39;s code is following:

        // rpc_json_client.go

        package main

        import (
            &quot;fmt&quot;
            &quot;log&quot;
            &quot;net&quot;
            &quot;net/rpc&quot;
            &quot;net/rpc/jsonrpc&quot;
        )

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

        type Arithmetic int // Used as RPC Service called &#39;Arithmetic&#39;

        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 = &quot;tcp&quot;
            srv_host = &quot;0.0.0.0&quot;
            srv_port = &quot;3000&quot;
            srv_addr = srv_host + &quot;:&quot; + srv_port
            //srv_path = &quot;/&quot;

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

            // Client
            client = jsonrpc.NewClient(connection)

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

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

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


Once again. This golang program works fine.

But the next thing I cannot understand.

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

Please, give me some advice or the reason for such an error. What is wrong in the raw request?

Thanks in advance!

</details>


# 答案1
**得分**: 0

你的代码看起来没问题。

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

尝试使用以下有效载荷,应该可以正常工作:

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


(注意实际参数被包含在`[`和`]`中)

<details>
<summary>英文:</summary>

Your code seems fine.

But in the request, `params` is expected to be an array containing the actual parameters.

Try with the following payload and it should work:

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

(Note the &quot;[&quot; and &quot;]&quot; enclosing the actual param)


</details>



huangapple
  • 本文由 发表于 2017年7月4日 02:50:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/44892236.html
匿名

发表评论

匿名网友

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

确定