英文:
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 (
"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
}
}
//------------------------------------------------------------------------------
The working and super simple JSON-RPC client's code is following:
// 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
}
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 '^]'.
{
"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 {}"}
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:
{
"jsonrpc":"2.0",
"method":"Arithmetic.Multiply",
"params": [ { "A": 5, "B": 6 } ],
"id":1
}
(Note the "[" and "]" enclosing the actual param)
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论