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

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

JSON-RPC, "cannot unmarshal object"

问题

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

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

  1. // rpc_json_server.go
  2. package main
  3. import (
  4. "log"
  5. "net"
  6. "net/http"
  7. "net/rpc"
  8. "net/rpc/jsonrpc"
  9. )
  10. //------------------------------------------------------------------------------
  11. // 类型定义
  12. //------------------------------------------------------------------------------
  13. type Arithmetic int // 作为名为'Arithmetic'的RPC服务
  14. type Arguments struct {
  15. A int
  16. B int
  17. }
  18. type Result int
  19. //------------------------------------------------------------------------------
  20. // 方法定义
  21. //------------------------------------------------------------------------------
  22. func (t *Arithmetic) Multiply(args *Arguments, res *Result) error {
  23. *res = Result(args.A * args.B)
  24. return nil
  25. }
  26. //------------------------------------------------------------------------------
  27. func main() {
  28. var srv *rpc.Server
  29. var err error
  30. var arith *Arithmetic
  31. var listener net.Listener
  32. var codec rpc.ServerCodec
  33. var srv_conntype, srv_host, srv_port, srv_addr, srv_path string
  34. var srv_debugPath string
  35. var connection net.Conn
  36. srv_conntype = "tcp"
  37. srv_host = "0.0.0.0"
  38. srv_port = "3000"
  39. srv_addr = srv_host + ":" + srv_port
  40. srv_path = "/"
  41. srv_debugPath = "/debug"
  42. // 创建Server,注册Service
  43. srv = rpc.NewServer()
  44. arith = new(Arithmetic)
  45. err = srv.Register(arith)
  46. if err != nil {
  47. log.Fatalf("错误。Service格式不正确。%s\r\n", err) //dbg
  48. }
  49. // 处理请求,监听端口
  50. srv.HandleHTTP(srv_path, srv_debugPath)
  51. listener, err = net.Listen(srv_conntype, srv_addr)
  52. if err != nil {
  53. log.Fatalf("错误。无法监听%s。%s\r\n", srv_addr, err) //dbg
  54. }
  55. log.Printf("已启动RPC处理程序,监听地址:%s。\r\n", srv_addr) //dbg
  56. // 处理请求
  57. for {
  58. connection, err = listener.Accept()
  59. if err != nil {
  60. log.Fatal(err)
  61. }
  62. codec = jsonrpc.NewServerCodec(connection)
  63. go srv.ServeCodec(codec)
  64. }
  65. err = http.Serve(listener, nil)
  66. if err != nil {
  67. log.Fatalf("Serve错误。%s\r\n", err) //dbg
  68. }
  69. }
  70. //------------------------------------------------------------------------------
  71. 这是一个工作正常且非常简单的JSON-RPC客户端的代码
  72. ```go
  73. // rpc_json_client.go
  74. package main
  75. import (
  76. "fmt"
  77. "log"
  78. "net"
  79. "net/rpc"
  80. "net/rpc/jsonrpc"
  81. )
  82. //------------------------------------------------------------------------------
  83. // 类型定义
  84. //------------------------------------------------------------------------------
  85. type Arithmetic int // 作为名为'Arithmetic'的RPC服务
  86. type Arguments struct {
  87. A int
  88. B int
  89. }
  90. type Result int
  91. //------------------------------------------------------------------------------
  92. // 方法定义
  93. //------------------------------------------------------------------------------
  94. func main() {
  95. var err error
  96. var srv_conntype, srv_host, srv_port, srv_addr string
  97. var client *rpc.Client
  98. var args Arguments
  99. var result Result
  100. var serviceName, methodName, funcName string
  101. var connection net.Conn
  102. srv_conntype = "tcp"
  103. srv_host = "0.0.0.0"
  104. srv_port = "3000"
  105. srv_addr = srv_host + ":" + srv_port
  106. // 连接RPC服务器
  107. connection, err = net.Dial(srv_conntype, srv_addr)
  108. if err != nil {
  109. log.Fatalf("错误。无法连接到%s。%s\r\n", srv_addr, err) //dbg
  110. }
  111. defer connection.Close()
  112. // 客户端
  113. client = jsonrpc.NewClient(connection)
  114. // 准备调用
  115. serviceName = "Arithmetic"
  116. methodName = "Multiply"
  117. funcName = serviceName + "." + methodName
  118. args.A = 7
  119. args.B = 8
  120. // 调用远程过程
  121. err = client.Call(funcName, args, &result)
  122. if err != nil {
  123. log.Fatalf("错误。%s\r\n", err) //dbg
  124. }
  125. // 显示结果
  126. fmt.Printf("[%d; %d] -> [%d].\r\n", args.A, args.B, result) //dbg
  127. }

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

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

  1. telnet localhost 3000
  2. Trying 127.0.0.1...
  3. Connected to localhost.
  4. Escape character is '^]'.
  5. {
  6. "jsonrpc":"2.0",
  7. "method":"Arithmetic.Multiply",
  8. "params": { "A": 5, "B": 6 },
  9. "id":1
  10. }
  11. {"id":1,"result":null,"error":"json: cannot unmarshal object into Go value of type [1]interface {}"}
  12. 请给我一些建议或解释这个错误的原因。原始请求中有什么问题?
  13. 提前感谢!
  14. <details>
  15. <summary>英文:</summary>
  16. 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.
  17. The working and super simple JSON-RPC server is described here:
  18. // rpc_json_server.go
  19. package main
  20. import (
  21. &quot;log&quot;
  22. &quot;net&quot;
  23. &quot;net/http&quot;
  24. &quot;net/rpc&quot;
  25. &quot;net/rpc/jsonrpc&quot;
  26. )
  27. //------------------------------------------------------------------------------
  28. // Types
  29. //------------------------------------------------------------------------------
  30. type Arithmetic int // Used as RPC Service called &#39;Arithmetic&#39;
  31. type Arguments struct {
  32. A int
  33. B int
  34. }
  35. type Result int
  36. //------------------------------------------------------------------------------
  37. // Methods
  38. //------------------------------------------------------------------------------
  39. func (t *Arithmetic) Multiply(args *Arguments, res *Result) error {
  40. *res = Result(args.A * args.B)
  41. return nil
  42. }
  43. //------------------------------------------------------------------------------
  44. func main() {
  45. var srv *rpc.Server
  46. var err error
  47. var arith *Arithmetic
  48. var listener net.Listener
  49. var codec rpc.ServerCodec
  50. var srv_conntype, srv_host, srv_port, srv_addr, srv_path string
  51. var srv_debugPath string
  52. var connection net.Conn
  53. srv_conntype = &quot;tcp&quot;
  54. srv_host = &quot;0.0.0.0&quot;
  55. srv_port = &quot;3000&quot;
  56. srv_addr = srv_host + &quot;:&quot; + srv_port
  57. srv_path = &quot;/&quot;
  58. srv_debugPath = &quot;/debug&quot;
  59. // Create Server, register Service
  60. srv = rpc.NewServer()
  61. arith = new(Arithmetic)
  62. err = srv.Register(arith)
  63. if err != nil {
  64. log.Fatalf(&quot;Error. Service Format is not correct. %s\r\n&quot;, err) //dbg
  65. }
  66. // Handle, listen
  67. srv.HandleHTTP(srv_path, srv_debugPath)
  68. listener, err = net.Listen(srv_conntype, srv_addr)
  69. if err != nil {
  70. log.Fatalf(&quot;Error. Can not listen on %s. %s\r\n&quot;, srv_addr, err) //dbg
  71. }
  72. log.Printf(&quot;Started RPC Handler at %s.\r\n&quot;, srv_addr) //dbg
  73. // Serve
  74. for {
  75. connection, err = listener.Accept()
  76. if err != nil {
  77. log.Fatal(err)
  78. }
  79. codec = jsonrpc.NewServerCodec(connection)
  80. go srv.ServeCodec(codec)
  81. }
  82. err = http.Serve(listener, nil)
  83. if err != nil {
  84. log.Fatalf(&quot;Serve Error. %s\r\n&quot;, err) //dbg
  85. }
  86. }
  87. //------------------------------------------------------------------------------
  88. The working and super simple JSON-RPC client&#39;s code is following:
  89. // rpc_json_client.go
  90. package main
  91. import (
  92. &quot;fmt&quot;
  93. &quot;log&quot;
  94. &quot;net&quot;
  95. &quot;net/rpc&quot;
  96. &quot;net/rpc/jsonrpc&quot;
  97. )
  98. //------------------------------------------------------------------------------
  99. // Types
  100. //------------------------------------------------------------------------------
  101. type Arithmetic int // Used as RPC Service called &#39;Arithmetic&#39;
  102. type Arguments struct {
  103. A int
  104. B int
  105. }
  106. type Result int
  107. //------------------------------------------------------------------------------
  108. // Methods
  109. //------------------------------------------------------------------------------
  110. func main() {
  111. var err error
  112. var srv_conntype, srv_host, srv_port, srv_addr string
  113. //var srv_path string
  114. var client *rpc.Client
  115. var args Arguments
  116. var result Result
  117. var serviceName, methodName, funcName string
  118. var connection net.Conn
  119. srv_conntype = &quot;tcp&quot;
  120. srv_host = &quot;0.0.0.0&quot;
  121. srv_port = &quot;3000&quot;
  122. srv_addr = srv_host + &quot;:&quot; + srv_port
  123. //srv_path = &quot;/&quot;
  124. // Connect to RPC Server
  125. connection, err = net.Dial(srv_conntype, srv_addr)
  126. if err != nil {
  127. log.Fatalf(&quot;Error. Can not connect to %s. %s\r\n&quot;, srv_addr, err) //dbg
  128. }
  129. defer connection.Close()
  130. // Client
  131. client = jsonrpc.NewClient(connection)
  132. // Prepare Call
  133. serviceName = &quot;Arithmetic&quot;
  134. methodName = &quot;Multiply&quot;
  135. funcName = serviceName + &quot;.&quot; + methodName
  136. args.A = 7
  137. args.B = 8
  138. // Call remote Procedure
  139. err = client.Call(funcName, args, &amp;result)
  140. if err != nil {
  141. log.Fatalf(&quot;Error. %s\r\n&quot;, err) //dbg
  142. }
  143. // Show Results
  144. fmt.Printf(&quot;[%d; %d] -&gt; [%d].\r\n&quot;, args.A, args.B, result) //dbg
  145. }
  146. Once again. This golang program works fine.
  147. But the next thing I cannot understand.
  148. telnet localhost 3000
  149. Trying 127.0.0.1...
  150. Connected to localhost.
  151. Escape character is &#39;^]&#39;.
  152. {
  153. &quot;jsonrpc&quot;:&quot;2.0&quot;,
  154. &quot;method&quot;:&quot;Arithmetic.Multiply&quot;,
  155. &quot;params&quot;: { &quot;A&quot;: 5, &quot;B&quot;: 6 },
  156. &quot;id&quot;:1
  157. }
  158. {&quot;id&quot;:1,&quot;result&quot;:null,&quot;error&quot;:&quot;json: cannot unmarshal object into Go value of type [1]interface {}&quot;}
  159. Please, give me some advice or the reason for such an error. What is wrong in the raw request?
  160. Thanks in advance!
  161. </details>
  162. # 答案1
  163. **得分**: 0
  164. 你的代码看起来没问题。
  165. 但是在请求中,`params` 应该是一个包含实际参数的数组。
  166. 尝试使用以下有效载荷,应该可以正常工作:

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

  1. (注意实际参数被包含在`[``]`中)
  2. <details>
  3. <summary>英文:</summary>
  4. Your code seems fine.
  5. But in the request, `params` is expected to be an array containing the actual parameters.
  6. Try with the following payload and it should work:
  7. {
  8. &quot;jsonrpc&quot;:&quot;2.0&quot;,
  9. &quot;method&quot;:&quot;Arithmetic.Multiply&quot;,
  10. &quot;params&quot;: [ { &quot;A&quot;: 5, &quot;B&quot;: 6 } ],
  11. &quot;id&quot;:1
  12. }
  13. (Note the &quot;[&quot; and &quot;]&quot; enclosing the actual param)
  14. </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:

确定