golang实现JSON-RPC 2.0 HTTP客户端通信插件库jsonrpc的使用

Golang 实现 JSON-RPC 2.0 HTTP 客户端通信插件库 jsonrpc 的使用

简介

这是一个基于 JSON-RPC 2.0 规范的 Golang 实现,通过 HTTP 协议进行 RPC 通信的客户端库。

Go Report Card Go build Codecov GoDoc GitHub license Mentioned in Awesome Go

安装

go get -u github.com/ybbus/jsonrpc/v3

快速开始

以下是一个简单的示例,展示如何获取和更新人员信息:

package main

import (
	"context"
	"github.com/ybbus/jsonrpc/v3"
)

type Person struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")

	var person *Person
	rpcClient.CallFor(context.Background(), &person, "getPersonById", 4711)

	person.Age = 33
	rpcClient.Call(context.Background(), "updatePerson", person)
}

详细使用

生成 JSON-RPC 请求

简单调用:

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    rpcClient.Call(ctx, "getDate")
    // 生成请求体: {"method":"getDate","id":0,"jsonrpc":"2.0"}
}

带参数的调用:

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    rpcClient.Call(ctx, "addNumbers", 1, 2)
    // 生成请求体: {"method":"addNumbers","params":[1,2],"id":0,"jsonrpc":"2.0"}
}

处理 JSON-RPC 响应

基本错误处理:

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    response, err := rpcClient.Call(ctx, "addNumbers", 1, 2)
    if err != nil {
        // 处理网络/HTTP错误
    }

    if response.Error != nil {
        // 处理RPC错误
        // 检查 response.Error.Code, response.Error.Message 和可选的 response.Error.Data
    }
}

获取响应结果:

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")
    response, _ := rpcClient.Call(ctx, "addNumbers", 1, 2)

    result, err := response.GetInt()
    if err != nil {
        // 结果无法解析为整数
    }

    // 其他基本类型获取方法:
    response.GetFloat()
    response.GetString()
    response.GetBool()
}

使用 CallFor() 便捷方法

type Person struct {
    Id   int    `json:"id"`
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")

    var person *Person
    err := rpcClient.CallFor(ctx, &person, "getPersonById", 123)

    if err != nil || person == nil {
        // 处理错误
    }

    fmt.Println(person.Name)
}

使用批量请求

func main() {
    rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc")

    response, _ := rpcClient.CallBatch(ctx, RPCRequests{
      NewRequest("myMethod1", 1, 2, 3),
      NewRequest("anotherMethod", "Alex", 35, true),
      NewRequest("myMethod2", &Person{
        Name: "Emmy",
        Age: 4,
      }),
    })
}

自定义 HTTP 客户端

func main() {
	proxyURL, _ := url.Parse("http://proxy:8080")
	transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)}

	httpClient := &http.Client{
		Transport: transport,
	}

	rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{
		HTTPClient: httpClient,
	})

	// 请求现在会使用代理
}

基本认证

func main() {
    rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{
		CustomHeaders: map[string]string{
			"Authorization": "Basic " + base64.StdEncoding.EncodeToString([]byte("myUser"+":"+"mySecret")),
		},
	})
    response, _ := rpcClient.Call(ctx, "addNumbers", 1, 2) // 发送带 Authorization 头的请求
}

OAuth 认证

func main() {
		credentials := clientcredentials.Config{
    		ClientID:     "myID",
    		ClientSecret: "mySecret",
    		TokenURL:     "http://mytokenurl",
    	}

    	rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{
    		HTTPClient: credentials.Client(context.Background()),
    	})

	// 请求现在会获取并使用 OAuth token
}

高级配置

允许响应中的未知字段

func main() {
	rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{
        AllowUnknownFields: true,
	})

	// 现在响应中允许未知字段
}

修改默认请求 ID

func main() {
    rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{
        DefaultRequestID: 1,
    })

    // 请求现在默认 ID 为 1
}

以上是 jsonrpc 库的基本使用方法和示例代码。这个库提供了灵活的配置选项,可以满足各种 JSON-RPC 2.0 客户端通信需求。


更多关于golang实现JSON-RPC 2.0 HTTP客户端通信插件库jsonrpc的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现JSON-RPC 2.0 HTTP客户端通信插件库jsonrpc的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang实现JSON-RPC 2.0 HTTP客户端通信

JSON-RPC 2.0是一种轻量级的远程过程调用协议,使用JSON作为数据格式。在Golang中,我们可以使用标准库net/rpc/jsonrpc来实现JSON-RPC客户端通信。

基本使用

1. 标准库实现

Golang标准库提供了net/rpc/jsonrpc包,但它是基于TCP连接的。对于HTTP通信,我们需要稍作封装:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

type Request struct {
	Jsonrpc string        `json:"jsonrpc"`
	Method  string        `json:"method"`
	Params  []interface{} `json:"params"`
	ID      int           `json:"id"`
}

type Response struct {
	Jsonrpc string      `json:"jsonrpc"`
	Result  interface{} `json:"result,omitempty"`
	Error   *RpcError   `json:"error,omitempty"`
	ID      int         `json:"id"`
}

type RpcError struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

func Call(url string, method string, params []interface{}) (*Response, error) {
	request := Request{
		Jsonrpc: "2.0",
		Method:  method,
		Params:  params,
		ID:      1,
	}

	payload, err := json.Marshal(request)
	if err != nil {
		return nil, err
	}

	resp, err := http.Post(url, "application/json", bytes.NewBuffer(payload))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var response Response
	err = json.NewDecoder(resp.Body).Decode(&response)
	if err != nil {
		return nil, err
	}

	if response.Error != nil {
		return nil, fmt.Errorf("RPC error: %v (code: %d)", response.Error.Message, response.Error.Code)
	}

	return &response, nil
}

func main() {
	response, err := Call("http://example.com/rpc", "add", []interface{}{1, 2})
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Printf("Result: %v\n", response.Result)
}

2. 使用第三方库

更推荐使用成熟的第三方库如github.com/ybbus/jsonrpc,它提供了更完善的HTTP JSON-RPC 2.0客户端实现:

package main

import (
	"fmt"
	"github.com/ybbus/jsonrpc/v2"
)

func main() {
	// 创建RPC客户端
	rpcClient := jsonrpc.NewClient("http://example.com/rpc")

	// 同步调用
	response, err := rpcClient.Call("add", 1, 2)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	// 处理响应
	var result int
	err = response.GetObject(&result)
	if err != nil {
		fmt.Println("Error parsing result:", err)
		return
	}

	fmt.Printf("Result: %d\n", result)

	// 异步调用
	asyncCall := rpcClient.Go("add", []int{3, 4}, nil)
	select {
	case reply := <-asyncCall.Done:
		if reply.Error != nil {
			fmt.Println("Async error:", reply.Error)
			return
		}
		var asyncResult int
		reply.GetObject(&asyncResult)
		fmt.Printf("Async result: %d\n", asyncResult)
	}
}

高级功能

1. 自定义HTTP客户端

rpcClient := jsonrpc.NewClientWithOpts("http://example.com/rpc", &jsonrpc.RPCClientOpts{
	HTTPClient: &http.Client{
		Timeout: 30 * time.Second,
		Transport: &http.Transport{
			MaxIdleConns:        10,
			IdleConnTimeout:     30 * time.Second,
			DisableCompression:  true,
		},
	},
	CustomHeaders: map[string]string{
		"X-Custom-Header": "value",
	},
})

2. 批量请求

batch := []jsonrpc.RPCRequest{
	{
		Method: "add",
		Params: []int{1, 2},
	},
	{
		Method: "subtract",
		Params: []int{5, 3},
	},
}

responses, err := rpcClient.CallBatch(batch)
if err != nil {
	fmt.Println("Batch error:", err)
	return
}

for _, response := range responses {
	var result int
	response.GetObject(&result)
	fmt.Printf("Method %s result: %d\n", response.RPCRequest.Method, result)
}

3. 错误处理

response, err := rpcClient.Call("divide", 10, 0)
if err != nil {
	if rpcErr, ok := err.(*jsonrpc.RPCError); ok {
		fmt.Printf("RPC error (code %d): %s\n", rpcErr.Code, rpcErr.Message)
	} else {
		fmt.Println("Network/other error:", err)
	}
	return
}

最佳实践

  1. 连接池管理:重用HTTP客户端以减少连接开销
  2. 超时设置:为RPC调用设置合理的超时时间
  3. 错误重试:实现简单的重试机制处理暂时性错误
  4. 日志记录:记录请求和响应以便调试
  5. 指标监控:跟踪RPC调用的延迟和成功率

总结

Golang中实现JSON-RPC 2.0 HTTP客户端通信有多种方式,从简单的标准库封装到使用功能丰富的第三方库。github.com/ybbus/jsonrpc库提供了最完整的实现,包括批量请求、异步调用等高级功能,是大多数场景下的最佳选择。

对于简单的需求,标准库封装可能足够;但对于生产环境,建议使用成熟的第三方库以获得更好的稳定性、性能和功能支持。

回到顶部