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

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

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:

确定