You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang客户端实现WebSocket上的JSON-RPC2.0遇阻求助

解决Golang WebSocket JSON-RPC2.0客户端整合问题

看起来你踩了几个常见的坑:标准库的net/rpc/jsonrpc是JSON-RPC 1.0实现,和你需要的2.0版本不兼容,而且直接用WebSocket的底层TCP连接会绕过WebSocket的帧解析逻辑,导致数据格式完全不对。另外手动序列化参数的操作也是多余的,反而会引发格式错误。下面给你一步步梳理解决方案:

核心问题诊断

  1. 版本不兼容:net/rpc/jsonrpc只支持JSON-RPC 1.0,不满足你的2.0需求,而且它的通信模型是基于裸TCP/HTTP,无法直接适配WebSocket的帧协议。
  2. 连接误用:conn.UnderlyingConn()返回的是原始TCP连接,没有处理WebSocket的帧封装,直接传给jsonrpc客户端会导致数据传输混乱。
  3. 参数处理错误:client.Call会自动序列化参数,你手动json.Marshal后再传入,会导致参数被双重序列化,服务器无法解析。

推荐解决方案:使用以太坊RPC库(原生支持WebSocket + JSON-RPC2.0)

以太坊的go-ethereum/rpc库是成熟的JSON-RPC2.0实现,原生支持WebSocket客户端和服务器,完全匹配你的需求。

步骤1:安装依赖

go get github.com/ethereum/go-ethereum/rpc

步骤2:客户端代码实现

package main

import (
    "context"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
)

// 定义请求参数结构体,和服务器保持一致
type Params struct {
    Name string `json:"name"`
}

// 定义响应结构体,根据服务器返回的字段调整
type Result struct {
    Message string `json:"message"`
}

func main() {
    // 建立WebSocket RPC连接
    client, err := rpc.DialWebsocket(context.Background(), "ws://127.0.0.1:8080/ws_rpc", "")
    if err != nil {
        log.Fatalf("WebSocket连接失败: %v", err)
    }
    defer client.Close()

    var resp Result
    // 调用远程方法:第一个参数是接收结果的指针,第二个是方法名,第三个是原始参数结构体
    err = client.Call(&resp, "some_handler", Params{Name: "newuser"})
    if err != nil {
        log.Fatalf("RPC调用失败: %v", err)
    }

    log.Printf("收到响应: %+v", resp)
}

步骤3:配套服务器代码(供参考)

如果你的服务器还没实现,也可以用同一个库快速搭建:

package main

import (
    "context"
    "log"
    "net/http"

    "github.com/ethereum/go-ethereum/rpc"
)

type RPCService struct{}

// 定义远程调用方法:参数要包含context,输入参数,返回结果和错误
func (s *RPCService) SomeHandler(ctx context.Context, params Params) (Result, error) {
    return Result{Message: "Hello, " + params.Name}, nil
}

type Params struct {
    Name string `json:"name"`
}

type Result struct {
    Message string `json:"message"`
}

func main() {
    rpcServer := rpc.NewServer()
    // 注册服务(空字符串表示不使用服务前缀,直接用方法名调用)
    if err := rpcServer.RegisterName("", &RPCService{}); err != nil {
        log.Fatalf("注册RPC服务失败: %v", err)
    }

    // 绑定WebSocket路由
    http.HandleFunc("/ws_rpc", func(w http.ResponseWriter, r *http.Request) {
        rpcServer.ServeHTTP(w, r)
    })

    log.Println("服务器启动在 :8080")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatalf("服务器启动失败: %v", err)
    }
}

关键注意事项

  • 不要手动序列化参数:RPC库会自动处理JSON序列化,手动Marshal会导致参数被包裹成字符串,服务器无法解析。
  • 确保客户端和服务器使用相同的JSON-RPC版本:2.0版本的请求格式包含jsonrpc: "2.0"字段,这是1.0版本没有的。
  • 避免直接操作WebSocket底层连接:WebSocket有自己的帧协议,必须通过库提供的接口读写数据,不能跳过帧解析逻辑。

内容的提问来源于stack exchange,提问作者tristram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:22:04